c# - 流畅的nhibernate级联删除到已连接子类的集合

标签 c# hibernate nhibernate fluent-nhibernate cascading-deletes

这里是流畅的 nhibernate 新用户,我有一个带有父类的模型,该模型包含子类子类的集合(使用 TablePerSubClass 继承)。当尝试通过仅在父对象上调用删除来测试级联删除时,我在子表与其连接子类表之间收到约束错误。为了证明...

    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 之间的功能差异...或更准确地说(忽略保存/更新)部分)什么情况下前者不能处理而需要指定后者?

最佳答案

引用约束的问题与我们没有正确设置父子关系有关。

我。不仅 child 应该/必须了解 parent ,而且 parent 也必须了解其 child :

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);

上面的代码和级联映射足以让 NHibernate 调用:

session.SaveOrUpdate(p);

和Parent p、Child c1 和ExtendChild c2 ...全部都将被持久化。

如果我们在one内部继续 session ,则可以删除父p的现有实例:

session.Delete(p) 

这也会触发删除所有子级 - 因为父级确实知道它们:并为它们调用级联...

二.级联必须仅由 NHibernate 驱动,而不是由 DB 驱动。

我们还必须删除 ForeignKeyCascadeOnDelete,它实际上会使用 SQL Server native 级联创建数据库脚本...在本例中不需要这样做。

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() 确保 session 确实保留所有更改
  • 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);

如果约束与我们新创建的子项有关,这将完成工作......

关于c# - 流畅的nhibernate级联删除到已连接子类的集合,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25160155/

相关文章:

java - 使用 Gilead 保留带有继承的类

nhibernate - SessionFactory - 多个数据库的一个工厂

c# - 如何使用 nhibernate 通过递归自连接 SQL 获得最佳性能

sql - NHibernate 不一致的 sql 列别名

c# - 检测导航事件 blazor webassembly

c# - 如何从 C# 中的 SQL 存储过程中检索结果集和 PRINT 消息?

c# - 有效地将字节数组转换为十进制

c# - 具有依赖属性的 ContentPresenter 和 Datatemplates

java - 使用 EntityManager 从 EJB 访问 Hibernate Session

java - 当所有@OneToMany都是cascade=ALL时,org.hibernate.TransientObjectException