NHibernate cascade =“all-delete-orphan”正在删除非孤立的行

时间:2011-10-25 00:43:06

标签: c# nhibernate fluent-nhibernate

当使用cascade =“all-delete-orphan”时,NHibernate正在删除一个没有孤立的子行 - 它只是被移动到一个新的父级。

using (var session = sessionFactory.OpenSession())
{
    using (var transaction = session.BeginTransaction())
    {
        // Get the store we're moving him to 
        Store newStore = session.QueryOver<Store>().Where(...).SingleOrDefault();

        // Get existing employee 
        Employee jack = session.QueryOver<Employee>().Where(...).SingleOrDefault();

        // Do the move
        jack.Store.Staff.Remove(jack);
        jack.Store = newStore;
        jack.Store.Staff.Add(jack);

        transaction.Commit(); 
    }
}

提交时,会生成一个DELETE语句以从数据库中删除“jack”。如果'杰克'实际上是孤儿,这种行为是有道理的,但他现在应该乐意分配到他的新店。

如果我将级联更改为“all”,则会生成预期的UPDATE语句,并且可以按预期快速重新分配“jack”。但是,这会导致真正的孤立行保留在数据库中,这是不可接受的。

这是一个错误还是我做错了什么?

以下是课程:

public class Store
{
    public virtual Guid Id { get; private set; }
    public virtual string Name { get; set; }
    public virtual IList<Employee> Staff { get; set; }
}

public class Employee
{
    public virtual Guid Id { get; private set; }
    public virtual string FirstName { get; set; }
    public virtual string LastName { get; set; }
    public virtual Store Store { get; set; }
}

和FluentNHibernate映射:

public class EmployeeMap : ClassMap<Employee>
{
    public EmployeeMap()
    {
        Id(x => x.Id).GeneratedBy.Guid();
        Map(x => x.FirstName);
        Map(x => x.LastName);
        References(x => x.Store);
    }
}

public class StoreMap : ClassMap<Store>
{
    public StoreMap()
    {
        Id(x => x.Id).GeneratedBy.Guid();
        Map(x => x.Name);
        HasMany(x => x.Staff)
          .Inverse()
          .Cascade.AllDeleteOrphan();
    }
}

更新

在对此进行了一些测试后,它似乎确实是一个错误,因为加载对象的顺序会改变结果(请注意,在这两种情况下,移动员工都按上述方式完成):

1)加载存储B,加载存储A,在A.Staff中查找员工,将员工移动到B. ==&GT; 删除员工(不会抛出异常,不会重新插入员工)

2)加载存储A,加载存储B,在A.Staff中查找员工,将员工移动到B. ==&GT; ObjectDeletedException (已删除的对象将通过级联重新保存(从关联中删除已删除的对象))

第二种情况似乎是@Cole W提到的场景,讨论了herehere以及NHibernate中已知的孤儿处理限制。

但是,第一种情况似乎是一个错误。根据我的理解,不应该有一个场景,其中加载对象的顺序改变了NHibernate所做的数据库更改。它似乎是一个可能导致数据丢失的错误。

更新2

鉴于依赖于加载顺序的不一致行为和数据丢失的可能性,我将其记录为bug in NHibernate JIRA。错误报告具有完整的代码和映射来证明问题。

2 个答案:

答案 0 :(得分:5)

这实际上似乎是使用NHibernate的常见问题。查看这些文章,看看它们是否对您有所帮助。

查看此SO文章:Fluent NHibernate exception moving objects between collections

该文章中还有Fabio Maulo撰写的这篇文章:
http://fabiomaulo.blogspot.com/2009/09/nhibernate-tree-re-parenting.html

答案 1 :(得分:0)

问题很可能是由于覆盖了多个引用而没有告诉NHibernate发生了什么

在我们等待更新的Q时快速刺入它(请参阅我的评论,找到缺少的员工属性)我建议您更改查询,以便直接询问Store而不是使用商店导航器在您的Employee对象上。从Store.Staff集合中删除jack,发出session.SaveOrUpdate(store),然后尝试覆盖jack.Store对新的SaveOrUpdate引用(发出另一个{{1}}然后再提交事务)