期望的行为:
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月2日)
以下是在级联为“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"); }
更新(2/11/2014) – Radim在下面的回答中是正确的. NHibernate没有删除孩子们.它使他们与父母脱离关系.
解决方法
您在查询更新中显示的测试已经证明:
If the
parent.Children
is set tonull
and persited,it will have NO children – next time accessed.
让我解释一下发生了什么,让我使用一些虚拟语言(注意我使用父母和孩子来简化)
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
我们可以看到,由于映射保存更新,NHibernate通过删除引用确实处理了这种情况.实际上通过UPDATing子表
4)再次加载Parent
parent = session.Get<Parent>(1); // EMPTY -- is true: IsEmpty() Assert.IsTrue(parent.Children.IsEmpty());
摘要:
正如我们在上面看到的那样,NHibernate正在做着映射和预期的事情.没有删除.只是更新,删除引用
这个答案的上一部分
答案是:改变你的公共int?保存(…)实施. NHibernate级联按预期工作,请在此处阅读更多内容Ayende,NHibernate Cascades: the different between all,all-delete-orphans and save-update
首先看看上面的陈述:
DESIRED BEHAVIOR:
1) Cascade any changes to the collection (whether in the parent was retrieved by NHibernate or not).
2) Do not delete objects even if the parent does not have a collection of children.
大胆的部分是原因,为什么Cascade概念不起作用.因为:
Cascade makes sense only if an operation on
the existing parent is cascaded / repeated / passed
the existing/known child(children)
NHiberante级联实现确实以这种方式工作:9.9. Lifecyles and object graphs(摘录)
Mapping … with
cascade="all"
marks the association as a parent/child style relationship where save/update/deletion of the parent results in save/update/deletion of the child(ren). … A child which becomes unreferenced by its parent is not automatically deleted,except in the case of a<one-to-many>
association mapped with cascade=”all-delete-orphan”…
不仅没有删除它.如果未引用,则不会接收任何类型的级联操作的触发器.
建议:
调整Save()方法,做两个操作:
>更新父级>找到“孩子”或更好 – 与某种程度相关的项目.加载它们调整它们,并调用session.Flush().对ISession引用的对象的任何更改都将保留.
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。