流畅非hibernate级联删除到连接子类的集合
本文关键字:连接 子类 集合 删除 hibernate 级联 | 更新日期: 2023-09-27 18:16:34
新用户流畅的nhibernate在这里,我有一个父类的模型,持有子类的孩子的集合(使用TablePerSubClass继承)。当试图通过仅在父对象上调用delete来测试级联删除时,我得到子表与其连接的子类表之间的约束错误。为了演示…
public class ParentMap : ClassMap<Parent> {
public ParentMap() {
Id(x => x.Id);
HasMany(x => x.Children)
.Cascade.AllDeleteOrphan()
.ForeignKeyCascadeOnDelete()
.Inverse();
}
}
public class ChildMap : ClassMap<Child> {
public ChildMap() {
Id(x => x.Id);
References(x => x.Parent).Not.Nullable();
}
}
public class ExtendedChildMap : SubclassMap<ExtendedChild> {
public ExtendedChildMap() {
Map(x => x.extraFeature);
}
}
使用以下代码进行单元测试时…
using (var session = sessionFactory.OpenSession()) {
using (var transaction = session.BeginTransaction()) {
var p = new Parent();
var c1 = new Child() { Parent = p };
var c2 = new ExtendedChild() { Parent = p };
session.SaveOrUpdate(p);
session.SaveOrUpdate(c1);
session.SaveOrUpdate(c2);
Assert.IsTrue(session.Query<Parent>().Count() == 1);
Assert.IsTrue(session.Query<Child>().Count() == 2);
Assert.IsTrue(session.Query<ExtendedChild>().Count() == 1);
session.Delete(p);
Assert.IsTrue(session.Query<Parent>().Count() == 0);
}
}
使用
的最后断言测试失败The DELETE statement conflicted with the REFERENCE constraint "FKDB46742824B330ED". The conflict occurred in database "testDB", table "dbo.ExtendedChild", column 'Child_id'
如果集合只包含基类Child对象,则按预期工作,但是当添加派生的ExtendedChild时,删除似乎不会传播到基类。感觉我在这里错过了一些明显的东西,但我仍然没有设法解决这个问题,经过一个很好的搜索。
最后,我也仍然不是100%清楚Cascade.AllDeleteOrphan
和ForeignKeyCascadeOnDelete
之间的功能差异…或者更准确地说(忽略保存/更新部分),如果前者不能处理,而需要指定后者,会发生什么情况?
引用约束的问题与我们没有正确设置父子关系有关。
。不仅孩子应该/必须知道父母的情况,而且父母也必须知道孩子的情况:
var p = new Parent();
// assign parent to children
var c1 = new Child() { Parent = p };
var c2 = new ExtendedChild() { Parent = p };
// assign children to parent as well
p.Children.Add(c1);
p.Children.Add(c2);
上面的代码和cascade的映射足以让NHibernate调用:
session.SaveOrUpdate(p);
和Parent p
, Child c1
和ExtendedChild c2
…
如果我们在内部,一个继续会话,父p
的现有实例可以被删除:
session.Delete(p)
,这也会触发所有子节点的删除——因为父节点知道它们:并为它们调用级联…
二世。级联必须只由NHibernate驱动,而不是由DB驱动。
我们还必须删除 ForeignKeyCascadeOnDelete
,它有效地使用SQL Server本地级联创建DB脚本…在本例中,这是不需要的。
HasMany(x => x.Children)
...
// good and very helpful setting Cascade
.Cascade.AllDeleteOrphan()
// this is not what we want
// we do not need cascade on SQL Server side
// .ForeignKeyCascadeOnDelete()
单元测试:如何使上述测试完全工作的最佳方法是将创建和删除分开。为此,我们应该发出:
-
Flush()
确保会话持久化所有更改 -
Clear()
从一个新的干净表开始
结构可以像这样:
// as above... create Parent and Children - assign each to other
// and call parent to save
session.SaveOrUpdate(p);
// now we have to be sure, that the session will propagate
// all the changes into the DB
session.Flush();
// and reset all the settings:
session.Clear();
// now (re)load the parent to later let NHiberante do the correct cascade
var parentReloaded = session.Get<Parent>(p.Id);
// Delete all the related stuff
session.Delete(parentReloaded);
如果约束与我们新创建的子节点相关,这将完成工作....