2012-12-13 17 views
6

目的:
親の子リストへの変更がすべての子に伝播され、NHibernateが重い作業をするような親子関係を作成します。 親子関係は、自己参照テーブルの上にHas-Manyになります。カスケード削除を伴うNHibernateの多数のコレクションが失敗しています

問題:
親(ルート)オブジェクトを削除しようとすると、子オブジェクトを削除すると予想される動作ではなく、例外が発生します。私が使っているものの

バージョン:
のMicrosoft SQL Server Management Studioのバージョン10.0.4064.0
FluentNHibernateバージョン1.3
NHibernateのバージョン3.2.0.4

以下

ある現在のクラスのオブジェクトとテーブル構造Iのセットこの動作を複製するために使用しています。


// Entity 
class Task 
{ 
    ID { get; set; }  
    public virtual IList<Task> Children { get; set; } 
    public virtual byte[] Version { get; protected set; } 
    public virtual bool IsNew() { return ID <= 0; } 

    public Task() 
    { 
     this.Children = new System.Collections.Generic.List<Task>(); 
    } 
    // Other properties excluded for brevity 
} 

// Map 
class TaskMap : ClassMap<Task> 
{ 
    TaskMap() 
    { 
     Table("Task"); 

     Id(x => x.ID, "ID") 
      .GeneratedBy.HiLo(
       "NH_HiLo", "NextHigh", "100", 
       string.Format("TableName =  '{0}'", "Task")); 

     HasMany<Task>(x => x.Children) 
      .KeyColumn("ParentTaskID") 
      .Cascade.AllDeleteOrphan(); 

     // Other properties omitted for brevity 

     Version(x => x.Version) 
      .Not.Nullable() 
      .Generated.Always() 
      .Column("Version") 
      .CustomSqlType("timestamp"); 
    } 
} 

// Repository Delete Method: 
public virtual void Delete(Task value) 
{ 
    // CurrentSession is an ISession object that is currently open 
    using (var transaction = CurrentSession.BeginTransaction()) 
    { 
     try 
     { 
      CurrentSession.Delete(value); 
      transaction.Commit(); 
     } 
     catch (Exception) 
     { 
      transaction.Rollback(); 
      throw; 
     } 
    } 
} 

// Test Case using NUnit.Framework and FluentNHibernate.Testing: 
[TestFixtureSetUp] 
public void SetUpFixture() 
{ 
    _repository = new Repository(); 
} 

[Test] 
public void MappingTest() 
{ 
    var task = new Task(); // Omitted assigning other properties for brevity 

    var entity = new Task(); // Omitted assigning other properties for brevity 
    entity.Children.Add(task); 

    _entity = new PersistenceSpecification<Task>(_repository.CurrentSession) 
     .VerifyTheMappings(entity); 
}      

[TearDown] 
public void TearDown() 
{ 
    if (_entity != null && !_entity.IsNew()) 
    { 
     _repository.Delete(_entity); 
     _entity = null; 
    } 
} 

--Table Script: 
SET ANSI_NULLS ON 
GO 
SET QUOTED_IDENTIFIER ON 
GO 
CREATE TABLE [dbo].[Task](
    [ID] [bigint] NOT NULL, 
    [ParentTaskID] [bigint] NULL, -- Notice it DOES HAVE a NULLable FK  reference. 
    [Version] [timestamp] NOT NULL, 
    CONSTRAINT [PK_MyTable] PRIMARY KEY CLUSTERED(
     [ID] ASC 
    ) WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, 
     IGNORE_DUP_KEY = OFF,  ALLOW_ROW_LOCKS = ON, 
     ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] 
) ON [PRIMARY] 

GO 
ALTER TABLE [dbo].[Task] WITH CHECK ADD CONSTRAINT [FK_TasksChild_TasksParent] 
    FOREIGN KEY([ParentTaskID]) 
    REFERENCES [dbo].[Task] ([ID]) -- Notice the self table reference for child objects 
GO 
ALTER TABLE [dbo].[Task] CHECK CONSTRAINT [FK_TasksChild_TasksParent] 
GO 
上記の表とクラスと

、これらのオプションにカスケードを変更して、テストの解体時に指定した実行、これらの結果です。 Cascade.AllDeleteOrphanで



は、単に私がこの例外を取得する親オブジェクトに削除を呼び出す:

NHibernate.StaleObjectStateException was unhandled by user code 
Message=Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect): [Task#1015859] 
Source=NHibernate 
EntityName=Entities.Task 
StackTrace: 
    at NHibernate.Persister.Entity.AbstractEntityPersister.Check(Int32 rows, Object id, Int32 tableNumber, IExpectation expectation, IDbCommand statement) in d:\CSharp\NH\NH\nhibernate\src\NHibernate\Persister\Entity\AbstractEntityPersister.cs:line 2178 
    at NHibernate.Persister.Entity.AbstractEntityPersister.Delete(Object id, Object version, Int32 j, Object obj, SqlCommandInfo sql, ISessionImplementor session, Object[] loadedState) in d:\CSharp\NH\NH\nhibernate\src\NHibernate\Persister\Entity\AbstractEntityPersister.cs:line 2912 
    at NHibernate.Persister.Entity.AbstractEntityPersister.Delete(Object id, Object version, Object obj, ISessionImplementor session) in d:\CSharp\NH\NH\nhibernate\src\NHibernate\Persister\Entity\AbstractEntityPersister.cs:line 3095 
    at NHibernate.Action.EntityDeleteAction.Execute() in d:\CSharp\NH\NH\nhibernate\src\NHibernate\Action\EntityDeleteAction.cs:line 70 
    at NHibernate.Engine.ActionQueue.Execute(IExecutable executable) in d:\CSharp\NH\NH\nhibernate\src\NHibernate\Engine\ActionQueue.cs:line 136 
    at NHibernate.Engine.ActionQueue.ExecuteActions(IList list) in d:\CSharp\NH\NH\nhibernate\src\NHibernate\Engine\ActionQueue.cs:line 126 
    at NHibernate.Engine.ActionQueue.ExecuteActions() in d:\CSharp\NH\NH\nhibernate\src\NHibernate\Engine\ActionQueue.cs:line 174 
    at NHibernate.Event.Default.AbstractFlushingEventListener.PerformExecutions(IEventSource session) in d:\CSharp\NH\NH\nhibernate\src\NHibernate\Event\Default\AbstractFlushingEventListener.cs:line 249 
    at NHibernate.Event.Default.DefaultFlushEventListener.OnFlush(FlushEvent event) in d:\CSharp\NH\NH\nhibernate\src\NHibernate\Event\Default\DefaultFlushEventListener.cs:line 19 
    at NHibernate.Impl.SessionImpl.Flush() in d:\CSharp\NH\NH\nhibernate\src\NHibernate\Impl\SessionImpl.cs:line 1489 
    at NHibernate.Transaction.AdoTransaction.Commit() in d:\CSharp\NH\NH\nhibernate\src\NHibernate\Transaction\AdoTransaction.cs:line 190 
    at Repositories.Repository.Delete(Task value) in ..\Repositories\Repository.cs:line 22 
    at TaskTest.TearDown() in ..\Tests\TaskTest.cs:line 76 

子供のそれぞれを反復した後、再帰的にこれらの子供たちの子供たちを掘りそして下から上にそれぞれの子を削除しよう:

NHibernate.ObjectDeletedException was unhandled by user code 
Message=deleted object would be re-saved by cascade (remove deleted object from associations)[Task#1016061] 
Source=NHibernate 
EntityName=Entities.Task 
StackTrace: 
    at NHibernate.Impl.SessionImpl.ForceFlush(EntityEntry entityEntry) in d:\CSharp\NH\NH\nhibernate\src\NHibernate\Impl\SessionImpl.cs:line 914 
    at NHibernate.Event.Default.DefaultSaveOrUpdateEventListener.EntityIsTransient(SaveOrUpdateEvent event) in d:\CSharp\NH\NH\nhibernate\src\NHibernate\Event\Default\DefaultSaveOrUpdateEventListener.cs:line 140 
    at NHibernate.Event.Default.DefaultSaveOrUpdateEventListener.PerformSaveOrUpdate(SaveOrUpdateEvent event) in d:\CSharp\NH\NH\nhibernate\src\NHibernate\Event\Default\DefaultSaveOrUpdateEventListener.cs:line 76 
    at NHibernate.Event.Default.DefaultSaveOrUpdateEventListener.OnSaveOrUpdate(SaveOrUpdateEvent event) in d:\CSharp\NH\NH\nhibernate\src\NHibernate\Event\Default\DefaultSaveOrUpdateEventListener.cs:line 53 
    at NHibernate.Impl.SessionImpl.FireSaveOrUpdate(SaveOrUpdateEvent event) in d:\CSharp\NH\NH\nhibernate\src\NHibernate\Impl\SessionImpl.cs:line 2662 
    at NHibernate.Impl.SessionImpl.SaveOrUpdate(String entityName, Object obj) in d:\CSharp\NH\NH\nhibernate\src\NHibernate\Impl\SessionImpl.cs:line 549 
    at NHibernate.Engine.CascadingAction.SaveUpdateCascadingAction.Cascade(IEventSource session, Object child, String entityName, Object anything, Boolean isCascadeDeleteEnabled) in d:\CSharp\NH\NH\nhibernate\src\NHibernate\Engine\CascadingAction.cs:line 249 
    at NHibernate.Engine.Cascade.CascadeToOne(Object parent, Object child, IType type, CascadeStyle style, Object anything, Boolean isCascadeDeleteEnabled) in d:\CSharp\NH\NH\nhibernate\src\NHibernate\Engine\Cascade.cs:line 216 
    at NHibernate.Engine.Cascade.CascadeAssociation(Object parent, Object child, IType type, CascadeStyle style, Object anything, Boolean isCascadeDeleteEnabled) in d:\CSharp\NH\NH\nhibernate\src\NHibernate\Engine\Cascade.cs:line 181 
    at NHibernate.Engine.Cascade.CascadeProperty(Object parent, Object child, IType type, CascadeStyle style, Object anything, Boolean isCascadeDeleteEnabled) in d:\CSharp\NH\NH\nhibernate\src\NHibernate\Engine\Cascade.cs:line 148 
    at NHibernate.Engine.Cascade.CascadeCollectionElements(Object parent, Object child, CollectionType collectionType, CascadeStyle style, IType elemType, Object anything, Boolean isCascadeDeleteEnabled) in d:\CSharp\NH\NH\nhibernate\src\NHibernate\Engine\Cascade.cs:line 240 
    at NHibernate.Engine.Cascade.CascadeCollection(Object parent, Object child, CascadeStyle style, Object anything, CollectionType type) in d:\CSharp\NH\NH\nhibernate\src\NHibernate\Engine\Cascade.cs:line 201 
    at NHibernate.Engine.Cascade.CascadeAssociation(Object parent, Object child, IType type, CascadeStyle style, Object anything, Boolean isCascadeDeleteEnabled) in d:\CSharp\NH\NH\nhibernate\src\NHibernate\Engine\Cascade.cs:line 185 
    at NHibernate.Engine.Cascade.CascadeProperty(Object parent, Object child, IType type, CascadeStyle style, Object anything, Boolean isCascadeDeleteEnabled) in d:\CSharp\NH\NH\nhibernate\src\NHibernate\Engine\Cascade.cs:line 148 
    at NHibernate.Engine.Cascade.CascadeOn(IEntityPersister persister, Object parent, Object  anything) in d:\CSharp\NH\NH\nhibernate\src\NHibernate\Engine\Cascade.cs:line 126 
    at NHibernate.Event.Default.AbstractFlushingEventListener.CascadeOnFlush(IEventSource session, IEntityPersister persister, Object key, Object anything) in d:\CSharp\NH\NH\nhibernate\src\NHibernate\Event\Default\AbstractFlushingEventListener.cs:line 207 
    at NHibernate.Event.Default.AbstractFlushingEventListener.PrepareEntityFlushes(IEventSource session) in d:\CSharp\NH\NH\nhibernate\src\NHibernate\Event\Default\AbstractFlushingEventListener.cs:line 197 
    at NHibernate.Event.Default.AbstractFlushingEventListener.FlushEverythingToExecutions(FlushEvent event) in d:\CSharp\NH\NH\nhibernate\src\NHibernate\Event\Default\AbstractFlushingEventListener.cs:line 48 
    at NHibernate.Event.Default.DefaultFlushEventListener.OnFlush(FlushEvent event) in d:\CSharp\NH\NH\nhibernate\src\NHibernate\Event\Default\DefaultFlushEventListener.cs:line 18 
    at NHibernate.Impl.SessionImpl.Flush() in d:\CSharp\NH\NH\nhibernate\src\NHibernate\Impl\SessionImpl.cs:line 1489 
    at NHibernate.Transaction.AdoTransaction.Commit() in d:\CSharp\NH\NH\nhibernate\src\NHibernate\Transaction\AdoTransaction.cs:line 190 
    at Repositories.Repository.Delete(Task value) in ..\Repositories\Repository.cs:line 22 
    at Repositories.Repository.Delete(Task value) in ..\Repositories\Repository.cs:line 25 
    at Repositories.Repository.Delete(Task value) in ..\Repositories\Repository.cs:line 25 
    at Tests.TaskTest.TearDown() in ..\Tests\TaskTest.cs:line 76 
単純に削除呼び出し、Cascade.Allで

NHibernate.StaleObjectStateException was unhandled by user code 
Message=Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect): [Task#1015960] 
Source=NHibernate 
EntityName=Entities.Task 
StackTrace: 
    at NHibernate.Persister.Entity.AbstractEntityPersister.Check(Int32 rows, Object id, Int32 tableNumber, IExpectation expectation, IDbCommand statement) in d:\CSharp\NH\NH\nhibernate\src\NHibernate\Persister\Entity\AbstractEntityPersister.cs:line 2178 
    at NHibernate.Persister.Entity.AbstractEntityPersister.Delete(Object id, Object version, Int32 j, Object obj, SqlCommandInfo sql, ISessionImplementor session, Object[] loadedState) in d:\CSharp\NH\NH\nhibernate\src\NHibernate\Persister\Entity\AbstractEntityPersister.cs:line 2912 
    at NHibernate.Persister.Entity.AbstractEntityPersister.Delete(Object id, Object version, Object obj, ISessionImplementor session) in d:\CSharp\NH\NH\nhibernate\src\NHibernate\Persister\Entity\AbstractEntityPersister.cs:line 3095 
    at NHibernate.Action.EntityDeleteAction.Execute() in d:\CSharp\NH\NH\nhibernate\src\NHibernate\Action\EntityDeleteAction.cs:line 70 
    at NHibernate.Engine.ActionQueue.Execute(IExecutable executable) in d:\CSharp\NH\NH\nhibernate\src\NHibernate\Engine\ActionQueue.cs:line 136 
    at NHibernate.Engine.ActionQueue.ExecuteActions(IList list) in d:\CSharp\NH\NH\nhibernate\src\NHibernate\Engine\ActionQueue.cs:line 126 
    at NHibernate.Engine.ActionQueue.ExecuteActions() in d:\CSharp\NH\NH\nhibernate\src\NHibernate\Engine\ActionQueue.cs:line 174 
    at NHibernate.Event.Default.AbstractFlushingEventListener.PerformExecutions(IEventSource session) in d:\CSharp\NH\NH\nhibernate\src\NHibernate\Event\Default\AbstractFlushingEventListener.cs:line 249 
    at NHibernate.Event.Default.DefaultFlushEventListener.OnFlush(FlushEvent event) in d:\CSharp\NH\NH\nhibernate\src\NHibernate\Event\Default\DefaultFlushEventListener.cs:line 19 
    at NHibernate.Impl.SessionImpl.Flush() in d:\CSharp\NH\NH\nhibernate\src\NHibernate\Impl\SessionImpl.cs:line 1489 
    at NHibernate.Transaction.AdoTransaction.Commit() in d:\CSharp\NH\NH\nhibernate\src\NHibernate\Transaction\AdoTransaction.cs:line 190 
    at Repositories.Repository.Delete(Task value) in ..\Repositories\Repository.cs:line 22 
    at TaskTest.TearDown() in ..\Tests\TaskTest.cs:line 76 


、子供を反復子供の彼らのセットのそれぞれをクリアした後、私はこの例外を取得/保存親を削除します再帰的に、子供たちのそれぞれを反復それらの子供たちの子供たちを掘りとDELEしようとした後Cascade.AllDeleteOrphan

用として
同じ:親オブジェクトは、私はこの例外を取得しますteのボトムアップからの各子供:カスケード用として
同じ。親が正しく削除されますが、今、私は私にはないオブジェクトが孤立しています
も例外:

AllDeleteOrphan、子供を反復子供の彼らのセットのそれぞれをクリアした後、私はこの例外を取得/保存親を削除します欲しいです!


私は多くのブログ/ stackoverflowの質問/リソースのドキュメントに目を通していると、本当にこの問題の解決策を見ていません。
ここでは、私はすでにを通じて掘っているリンクのほんの一部です:


)私は!!カスケードを持つことの目的を奪うれ、手動ですべての子オブジェクトを削除するために持っているように思われてしまう)...技術的にNHibernateのは、それを生成し、それを割り当てますので、

投稿の多くは、関係を逆転させることを言いますが、.inverseを設定して、子どもとの関係を完全にすることは、ここでの目標ではありません!

私は何が欠けているのか分かりませんが、うまくいけば、これは私が見落としていることを修正するのは本当に簡単です。どんな助けでも大歓迎です!

答えて

5

がありません。 a)子には親がマッピングされていません。b)子がバージョン管理されています。c)コレクションが逆に設定されていません。(マップされた親なしの子では管理できないためです。おそらくバグが原因です。

DBサーバーによって生成された最新のtimestampを取得するには、バージョン管理でINSERTまたはUPDATEステートメントの後にSELECT ...が続きます。しかし、これは一つのケースでは発生しません:

  1. コレクション親が
  2. 子挿入
  3. 子バージョンは子供が更新さ
  4. DBから選択DBから選択
  5. 親バージョンを挿入されています(反転なし)を参照してください。
    • - いいえ - ch ildのバージョンが選択されていません...

関係の更新後の子バージョンはその後、ちょうどDBに増分1が...後でStaleExceptionがスローされる異なるので 。

あなたができる最善のは、親を持つようにマッピングを拡張...そしてそれは私がお返事に感謝

+0

逆作りです。これは、私が親と子供の関係を手作業で破る必要はないと思っていたが、それは避けられないように思えるので、私が聞いて欲しいと思っていたものではなかった。私は、ParentTask参照を追加し、deleteメソッドを微調整して子リストを調べ、親をnullに設定してネクタイを破棄し、最終的にCascade.AllDeleteOrphanが正しくオンになっている親タスクを削除することで合格とするテストを受けましたすべての孤立したタスクを削除します。再度、あなたの返事に感謝します。 –

関連する問題