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 没有删除子项。它将它们与父对象分离。
UPDATE,反映查询更改
您在查询更新中显示的测试已经证明:
如果
parent.Children设置为null并保留,它将没有子项 - 下次访问时。
让我解释一下发生了什么,让我使用一些虚拟语言(注意我正在使用Parent并Children使其简单)
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()方法,要做两个操作:
session.Flush(). 对ISession引用的对象的任何更改都将被保留。| 归档时间: |
|
| 查看次数: |
950 次 |
| 最近记录: |