2014-01-27 103 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()也发出删除。 –

相关问题