是否可以 Cascade.All() 除了删除?

Dan*_*man 5 c# nhibernate nhibernate-mapping

我分别获取一个对象列表(而不是来自 NHibernate)并将父对象 IEnumerable 设置为等于这个返回的对象。最初,我们只需要读取对象。然后我们只需要更新父级上的特定字段。最近,我们需要更新孩子的字段。到目前为止,SaveOrUpdate() 一切正常。现在,即使孩子的集合附加到分离的父对象(不使用 NHibernate),我也需要更新孩子。以下代码导致更新父级,但不更新子级。如果我都做了,那么如果父级没有集合,子级将被删除。我不想这样做,因为我担心无法解释这种行为的遗留用途。

期望的行为:
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;
}
Run Code Online (Sandbox Code Playgroud)

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");
        }
    }
Run Code Online (Sandbox Code Playgroud)

}

如果我更改Cascade.SaveUpdate()Cascade.All()更新工作,但也会删除。我想消除删除功能。

更新(1/27/2014):

我刚刚验证了映射时删除是级联的SaveUpdate(),所以这不是一个大问题,因为我没有更改现有功能。我仍然希望能够更新所有级联删除除外。如果可能的话,一个解决方案非常适合将来参考。

更新 (2/10/2014)

以下是验证当级联为“SaveUpdate()”时子项是否被删除的测试。它GetDocumentFieldDTOWithADO(DocumentFieldID)使用与 NHibernate 相同的事务,并且在第一次调用时(保存前)有 318 个 DocumentFieldOrgs,在保存后调用时为 0。也许测试有问题?它是否会因为我调用 Merge 而删除孩子?

    [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");        
    }
Run Code Online (Sandbox Code Playgroud)

更新 (2/11/2014) - Radim 在下面的回答中是正确的。NHibernate 没有删除子项。它将它们与父对象分离。

Rad*_*ler 1

UPDATE,反映查询更改

您在查询更新中显示的测试已经证明:

如果parent.Children设置为null并保留,它将没有子项 - 下次访问时。

让我解释一下发生了什么,让我使用一些虚拟语言(注意我正在使用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
Run Code Online (Sandbox Code Playgroud)

3) 现在,删除引用并检查 NHibernate 将做什么:

parent.Children = null;

session.Flush();
session.Clear();
Run Code Online (Sandbox Code Playgroud)

下面是执行的SQL语句:

exec sp_executesql N'UPDATE [schema].[Child_Table] 
      SET ParentId = null WHERE ParentId = @p0',N'@p0 int',@p0=1
Run Code Online (Sandbox Code Playgroud)

正如我们所看到的,由于映射save-update,NHibernate 确实通过删除引用来处理这种情况。事实上通过更新子表

4)Parent再次加载

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

// EMPTY -- is true: IsEmpty()
Assert.IsTrue(parent.Children.IsEmpty());
Run Code Online (Sandbox Code Playgroud)

简介: 正如我们在上面所看到的,NHibernate 正在执行映射的和预期的操作。没有删除。只是更新,删除参考

本答案的前一部分

答案是:改变你的public int? Save(...)实现。NHibernate 级联正在按预期工作,请在此处阅读更多内容Ayende,NHibernate 级联:全部、全部删除孤儿和保存更新之间的区别

首先看一下上面的声明:

期望的行为:
1) 级联对集合的任何更改(无论是否在父级中由 NHibernate 检索)。2) 即使父对象没有子集合,
也不要删除对象。

Cascade concept粗体部分是不起作用的原因。因为:


仅当现有父级上操作被级联/重复/传递给
现有/已知子级时,级联才有意义

NHiberante 级联实现确实是这样工作的:9.9。生命周期和对象图 (摘录)

映射...将cascade="all"关联标记为父/子样式关系,其中父项的保存/更新/删除会导致子项的保存/更新/删除。...未被其父级引用的子级不会自动删除,除非<one-to-many>关联映射为cascade=“all-delete-orphan”...

不仅没有被删除。如果未引用它,则它不会收到任何类型的级联操作的触发器。

建议:

调整Save()方法,要做两个操作:

  1. 更新父级
  2. 找到“孩子”或更好的东西——以某种方式相关的项目。加载它们调整它们,然后调用session.Flush(). 对ISession引用的对象的任何更改都将被保留。