2014-01-27 106 views
4

我得到的對象列表分別(而不是從NHibernate),並設置父對象的IEnumerable等於這個返回的對象。最初,我們只需要讀取對象。然後,我們需要僅更新父級上的特定字段。最近,我們需要更新孩子的領域。到目前爲止,SaveOrUpdate()都很好。現在,即使將子集合連接到分離的父對象(不使用NHibernate),我也需要更新子項。以下代碼會導致父級更新,但不會導致子級。如果我全部都做了,那麼如果父母沒有收藏,那麼這些孩子將被刪除。我不想這樣做,因爲我擔心這不會造成這種行爲的遺留使用。Cascade.All()是否可以刪除?

希望的行爲:
1.級聯對集合的任何更改(無論父級是否由NHibernate檢索)。 2.即使家長沒有孩子的集合,也不要刪除對象。

這可能嗎?

這是我們的NHibernate的保存方法:

[Transaction] 
public int? Save(DocumentFieldDTO entity, bool autoFlush) 
{ 
    var persisted = CurrentSession.Merge(entity); 

    entity.DocumentFieldID = persisted.DocumentFieldID; 
    if (autoFlush) { CurrentSession.Flush(); } 
    return entity.DocumentFieldID; 
} 

的DocumentFieldDTOMap是這樣的:

public class DocumentFieldDTOMap : EntityMapBase 
{ 

    public DocumentFieldDTOMap() 
    {  
     Table("DocumentField"); 

     Id(m => m.DocumentFieldID).GeneratedBy.Increment().UnsavedValue(null); 

     Map(x => x.Name); 

     Map(x => x.DocumentSectionID).Not.Update(); 
     // .... Lots of other fields ....// 

     HasMany(x => x.DocumentFieldOrgs) 
     .Cascade.SaveUpdate() 
     .LazyLoad() 
     .KeyColumn("DocumentFieldID"); 
     } 
    } 

}

如果我改變Cascade.SaveUpdate()Cascade.All()更新工作,也將刪除。我想消除刪除功能。

更新(2014年1月27日):

我只是驗證了刪除被級聯時映射爲SaveUpdate(),所以這不是一個大問題,因爲我不改變現有的功能。我仍然希望能夠更新所有級聯的EXCEPT刪除。如果可能的話,一個解決方案對於未來的參考很有用。

更新(2014年2月10日)

以下是驗證測試,當級聯「SaveUpdate()」孩子們都將被刪除。 GetDocumentFieldDTOWithADO(DocumentFieldID)使用與NHibernate相同的事務,並且在第一次調用時(保存前)有318個DocumentFieldOrgs,在保存後調用時爲0。也許這個測試有問題嗎?它是否因爲我打電話合併而刪除了孩子?

[Test] 
    public void Save_ShouldDeleteDocumentFieldOrgs_WhenSavingDocumentFieldWithoutDocFieldOrgsList() 
    { 
     //arrange 
     var expectedDocField = GetDocumentFieldDTOWithADO(DocumentFieldID); 
     expectedDocField.DocumentFieldOrgs = null; 

     //act 
     Repository.Save(expectedDocField, false); 
     SessionFactory.GetCurrentSession().FlushAndEvict(expectedDocField); 

     //assert 
     var actualDocField = GetDocumentFieldDTOWithADO(DocumentFieldID); 

     actualDocField.DocumentFieldOrgs.Should() 
      .BeEmpty("DocumentFieldOrgs should be deleted if the parent does not have a child collection");   
    } 

更新(2/11/2014) - Radim在他的回答中是正確的。 NHibernate沒有刪除這些孩子。它將它們與父母分離。

回答

1

UPDATE,反映了查詢的變化

您在查詢更新已經顯示的測試,已經證明:

如果parent.Children設置爲null和persited,它將有沒有孩子 - 下次訪問。

讓我解釋發生了什麼事,讓我用一些虛擬語言(注意我用的ParentChildren,使其簡單)

1)父子的映射是cascade="save-update"
這是一個NHibernate的信息,在創建或修改時,應該通過Save()或Update()調用來通過子集合

2)我們載入父

var session = ... // get a ISession for our test 
var parent = session.Get<Parent>(1); // e.g. DocumentFieldDTO 

// NOT Empty -- is true: IsNotEmpty() 
Assert.IsTrue(parent.Children.IsNotEmpty()); // e.g. DocumentFieldOrgs 

3)現在,除去參考,並檢查什麼的NHibernate會做:

parent.Children = null; 

session.Flush(); 
session.Clear(); 

這裏是執行的SQL語句:

exec sp_executesql N'UPDATE [schema].[Child_Table] 
     SET ParentId = null WHERE ParentId = @p0',N'@p0 int',@p0=1 

由於我們可以看到,由於映射save-update,NHibernate通過刪除引用來處理這種情況。事實上通過更新子表

4)負載Parent再次

parent = session.Get<Parent>(1); 

// EMPTY -- is true: IsEmpty() 
Assert.IsTrue(parent.Children.IsEmpty()); 

摘要: 正如我們在上面看到的,NHibernate的是做什麼的被映射,和預期。不刪除。只是一個更新,刪除該引用這個答案

答案是

前面部分:改變你的public int? Save(...)實現。 NHibernate的級聯工作正常,請在這裏閱讀更多Ayende, NHibernate Cascades: the different between all, all-delete-orphans and save-update

先看看上面的語句:

所需的行爲:
1)級聯到集合(任何變化是否在父被NHibernate檢索或不是)。
2)即使家長沒有兒童收集,也不要刪除對象。

大膽的部分是原因,爲什麼Cascade concept不起作用。因爲:

級聯纔有意義,如果現有的
操作父級聯/重複/通過
現有/已知兒童(兒童)

NHiberante級聯實現真的這樣做的工作:9.9. Lifecyles and object graphs(提取)

映射...與cascade="all"將關聯標記爲父/子樣式關係,其中保存/更新/刪除父項導致保存/更新/刪除子項(ren)。 ...... 成爲其母公司未被引用一個孩子是不會自動刪除,除了在<one-to-many>伴隨級聯映射的情況下=「全刪除,孤兒」 ......

它不僅是沒有刪除。如果它沒有被引用,它就不會收到任何類型的級聯操作的觸發器。

建議:

調整Save()方法,做兩個操作:

  1. 更新父
  2. 找到「孩子」或更好 - 在某種程度上相關的項目。加載他們調整他們,並且呼叫session.Flush()。對ISession引用的對象所做的任何更改都將被保留。
+0

我不明白你的迴應。如果父POCO對象沒有任何子POCO對象,NHibernate將從數據庫中刪除子記錄。我可以在保存實現中實現對孩子的變更管理,但我希望NHibernate能夠處理對象映射和變更管理。我想我希望有一些映射或SaveUpdate/Merge方法的實現可以指示NHibernate更新記錄,但絕不會刪除一個對象。您可以更好地控制您可以更新的內容,但不會被刪除。 –

+0

也許我不明白你的問題。級聯的工作方式如下:1)必須有父級傳遞給會話(SaveOrUpdate(父級)2)任何子級將按照此處所述進行級聯http://nhforge.org/doc/nh/en/index.html#manipulatingdata-圖表。 3)在'save-udpate'的情況下,永遠不會發布刪除。 4)如果「全部」刪除將只發布到當前已經存在的和刪除的項目。但在任何情況下,**都必須在會話中提供父母和子女的收集才能執行這些步驟。這是奇怪的:'..是否在父母被NHibernate檢索或不'這是否有幫助? –

+0

Radim,我會再次檢查,但在我的集成測試中,cascade.SaveUpdate()也發出刪除。 –

相關問題