当使用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提到的场景,讨论了here和here以及NHibernate中已知的孤儿处理限制。
但是,第一种情况似乎是一个错误。根据我的理解,不应该有一个场景,其中加载对象的顺序改变了NHibernate所做的数据库更改。它似乎是一个可能导致数据丢失的错误。
更新2
鉴于依赖于加载顺序的不一致行为和数据丢失的可能性,我将其记录为bug in NHibernate JIRA。错误报告具有完整的代码和映射来证明问题。
答案 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}}然后再提交事务)