我的代码正在累积来自用户的对象删除和更新,然后尝试一次性应用这些对象。在遇到麻烦的情况下,只有在没有孩子的情况下才会删除父母,但是必须手动删除子女,这是业务要求。
我可以使用以下代码重现该问题:
<class name="SomeClass" >
<id name="ID">
<generator class="native" />
</id>
<property name="Name" />
<many-to-one name="Parent" not-null="true" />
</class>
<class name="SomeParent" >
<id name="ID">
<generator class="native" />
</id>
<property name="Name" />
<set name="Children" batch-size="100" inverse="true">
<key column="Parent" not-null="true" />
<one-to-many class="SomeClass" />
</set>
</class>
public class SomeClass
{
public virtual int ID { get; set; }
public virtual string Name { get; set; }
public virtual SomeParent Parent { get; set; }
}
public class SomeParent
{
public virtual int ID { get; set; }
public virtual string Name { get; set; }
public virtual ISet<SomeClass> Children { get; set; }
}
using (var sessionFactory = cfg.BuildSessionFactory())
using (var session = sessionFactory.OpenSession())
{
var p = new SomeParent();
var obj = new SomeClass() { Parent = p };
session.Save(p);
session.Save(obj);
session.Flush();
}
using (var sessionFactory = cfg.BuildSessionFactory())
using (var session = sessionFactory.OpenSession())
using (var tx = session.BeginTransaction())
{
foreach (var p in session.CreateCriteria<SomeParent>().List<SomeParent>())
{
session.Delete(p);
}
foreach (var p in session.CreateCriteria<SomeClass>().List<SomeClass>())
{
session.Delete(p);
}
session.Flush();
tx.Commit();
}
当我交换两个Delete()
循环时,此示例有效。在我的应用程序中,我没有能够影响用户按下删除按钮的顺序。
如果我将cascade="delete"
添加到one-to-many
映射,则此示例也有效。这违反了父母在有孩子的情况下无法删除的业务要求。
我原本希望NHibernate为我处理这个订单。特别是因为映射中已经提供了所有必要的信息。我只是做错了什么,还是我必须“手动”对删除进行正确排序,以便NHibernate能够理解它们?
我正在使用NHibernate 3.2.0GA(从nuget构建3.2.0.4000)。
答案 0 :(得分:1)
我不明白你期望NHibernate应该能够处理这种情况。由于您没有指定级联设置,因此您必须自己处理删除。
我的建议是跟踪集合中的删除,并且在验证数据之前不要发出NHibernate Deletes。也就是说,为父对象和子对象创建MarkForDeletion方法。当用户单击“删除”时,这些方法会将对象添加到集合中。
当用户准备好提交事务时,循环遍历已标记为删除的子对象,将其从父级的子集合中删除,并将其对父对象的引用设置为null。然后遍历标记为删除的父对象,并验证其子集合是否为空。
如果数据有效,则可以删除父对象,并让级联设置(全部或全部删除 - 孤立)处理子记录。