2012-12-13 7 views
6

उद्देश्य:
माता-पिता के बच्चों के लिस्ट में संशोधन करने वाले बच्चों के माता-पिता की सूची में संशोधन सभी बच्चों के लिए प्रचारित होगा और एनएचबीर्नेट को भारी उठाने का काम होगा। माता-पिता संबंध एक आत्म संदर्भ तालिका पर Has-Many होगा।एनएचबर्ननेट हैस-कैस्केडिंग डिलीट्स के साथ कई संग्रह

समस्या:
अभिभावक (रूट) ऑब्जेक्ट को हटाने का कोई भी प्रयास बच्चे की वस्तुओं को हटाने के अपेक्षित व्यवहार के बजाय अपवाद का कारण बनता है। मैं उपयोग कर रहा हूँ सामान के

संस्करण:
Microsoft SQL सर्वर प्रबंधन स्टूडियो संस्करण 10.0.4064.0
FluentNHibernate संस्करण 1.3
NHibernate संस्करण 3.2.0.4

नीचे

है वर्तमान वर्ग वस्तुओं और तालिका संरचना मैं के सेट इस व्यवहार को दोहराने के लिए उपयोग कर रहा हूँ।


// 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 

, बच्चों के माध्यम से पुनरावृत्ति बच्चों के अपने सेटों में से प्रत्येक साफ़ करने के बाद, तो बचत/माता-पिता को हटाने मैं इस अपवाद प्राप्त करें: बस पर हटाना बुला

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 

Cascade.All साथ

, बच्चों में से प्रत्येक के माध्यम से पुनरावृत्ति, रिकर्सिवली उन बच्चों के बच्चों के माध्यम से खुदाई और डेले करने का प्रयास करने के बाद
Cascade.AllDeleteOrphan

के समान हैं: पैरेंट ऑब्जेक्ट मैं इस अपवाद प्रत्येक बच्चे को नीचे से ऊपर:
कैस्केड के समान ही।

AllDeleteOrphan, बच्चों के माध्यम से पुनरावृत्ति बच्चों के अपने सेटों में से प्रत्येक साफ़ करने के बाद, तो बचत/माता-पिता को हटाने मैं इस अपवाद:
कोई अपवाद: माता-पिता को सही ढंग से नष्ट कर दिया जाता है लेकिन अब मैं वस्तुओं है कि मुझे नहीं पता अनाथ है चाहते हैं!


मैं कई ब्लॉग/stackoverflow प्रश्न/संसाधन डॉक्स के माध्यम से देखा है और वास्तव में इस मुद्दे का समाधान नहीं देखा है।
यहाँ लिंक मैं पहले से ही के माध्यम से खोदा है की कुछ कर रहे हैं:


कई पदों में रिश्ते को बदलने और सेट करने का उल्लेख किया गया है। इसके विपरीत और बच्चे को रिश्ते बनाने का लक्ष्य पूरी तरह से लक्ष्य नहीं है!

मुझे नहीं पता कि मुझे क्या याद आ रहा है, लेकिन उम्मीद है कि यह ठीक करने के लिए वास्तव में कुछ आसान है जिसे मैं देख रहा हूं। किसी भी प्रकार के मदद की बहुत सराहना की जाएगी!

उत्तर

5

आप कुछ भी याद नहीं कर रहे हैं। यह आपके मानचित्रण का एक संयोजन है: ए) बच्चे के पास अभिभावक मैप नहीं होता है, बी) बच्चे का संस्करण होता है, सी) संग्रह को विपरीत के रूप में सेट नहीं किया जाता है (क्योंकि इसे मैप किए गए माता-पिता के बिना बच्चे द्वारा प्रबंधित नहीं किया जा सकता है) डी) और अंततः, अधिकांश एक बग के कारण संभावना है।

क्या होता है, यह है कि संस्करण के साथ, किसी भी INSERT या UPDATE कथन का चयन करके डीबी सर्वर द्वारा उत्पन्न नवीनतम timestamp प्राप्त करने के लिए किया जाता है। लेकिन इस एक मामले में ऐसा नहीं होता है:

  1. संग्रह माता पिता डाला जाता है
  2. माता पिता डीबी से चयनित संस्करण डीबी से चयनित
  3. बच्चे डाला
  4. बच्चे संस्करण
  5. बच्चे अद्यतन (कोई उलटा नहीं) माता-पिता को संदर्भित करने के लिए
    • - कुछ भी नहीं - ch हल्का संस्करण नहीं चुना गया है ...

क्योंकि संबंध अद्यतन के बाद बच्चे संस्करण अलग तो बस डीबी में वृद्धि एक ... बाद में StaleException फेंक दिया जाता है।

सबसे अच्छा आप कर सकते हैं मैपिंग को अभिभावक रखने के लिए ... और इसे उलटा

+0

मैं आपके उत्तर की सराहना करता हूं। यह वही नहीं था जो मैं सुनने की उम्मीद कर रहा था, हालांकि मैं उम्मीद कर रहा था कि मुझे माता-पिता और बच्चे के बीच संबंधों को मैन्युअल रूप से तोड़ना नहीं था, लेकिन ऐसा लगता है कि यह अपरिहार्य है। मुझे एक पैरेंट टास्क संदर्भ जोड़कर पास करने के लिए परीक्षा मिली और टाई को तोड़ने के लिए माता-पिता को शून्य पर सेट करने वाली बाल सूचियों के माध्यम से दोबारा खोदने के लिए हटाने की विधि को ट्विक करना और आखिरकार मूल कार्य को हटा दें, जब कैस्केड.एल्डेलेटेऑर्फन सही तरीके से चालू हो सभी अनाथ कार्यों को हटा देता है। फिर, आपके उत्तर के लिए धन्यवाद। –

संबंधित मुद्दे