fluent-nhibernate级联删除到join-subclassess的集合

时间:2014-08-06 12:15:06

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

这里有一个流畅的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.AllDeleteOrphanForeignKeyCascadeOnDelete之间的功能差异......或更确切地说(忽略保存/更新部分)是什么情况前者不处理并要求指定后者?

1 个答案:

答案 0 :(得分:1)

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

予。不仅孩子应该/必须知道父母,而且父母也必须被告知其子女:

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

和家长p,子c1和ExtendedChild c2 ...都会被保留。

如果我们在一个中继续会话,则可以删除现有的父p实例:

session.Delete(p) 

这也将触发所有孩子的删除 - 因为父母确实知道他们:并为他们调用级联 ......

II。级联必须仅由NHibernate驱动 - 而不是由DB驱动。

我们还必须删除 ForeignKeyCascadeOnDelete ,它有效地创建了带有SQL Server本机级联的数据库脚本......在这种情况下,这不是必需的。

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

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