删除父级和子级而不使用级联
我的代码正在累积用户的对象删除和更新,然后尝试一次性应用这些内容。在我遇到麻烦的情况下,业务要求是仅在没有子级时才删除父级,但必须手动删除子级。
我可以使用以下代码重现该问题:
映射:
<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)。
My code is accumulating object deletes and updates from the user and then tries to apply those in one shot. In the case I'm having troubles, it is a business requirement that the parent is only deleted if there are no children left, but the children have to be deleted manually.
I can reproduce the problem with the following code:
Mapping:
<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>
Entities:
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; }
}
Program:
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();
}
This example works when I exchange the two Delete()
loops. In my application I do not have the luxury of being able to influence the order in which users press the delete button.
This example also works, if I add cascade="delete"
to the one-to-many
mapping. This violates the business requirement that parents cannot be deleted while they still have children.
I would have expected NHibernate to handle this ordering for me. Especially as all necessary information is already available in the mapping. Am I simply doing something wrong or do I have to "manually" sort the deletes properly so that NHibernate will grok them?
I'm using NHibernate 3.2.0GA (build 3.2.0.4000 from nuget).
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
我不明白您期望 NHibernate 应该能够处理这种情况。由于您没有指定级联设置,因此您必须自己处理删除。
我的建议是跟踪集合中的删除,并且在验证数据之前不要发出 NHibernate 删除。即,为父对象和子对象创建 MarkForDeletion 方法。当用户单击删除时,这些方法将对象添加到集合中。
当用户准备好提交事务时,循环遍历已标记为删除的子对象,将它们从父对象的子对象集合中删除,并将它们对父对象的引用设置为 null。然后循环遍历标记为删除的父对象并验证其子集合是否为空。
如果数据有效,则可以删除父对象并让级联设置(全部或全部删除孤立)处理子记录。
I don't understand your expectation that NHibernate should be able to handle this scenario. Since you are not specifying a cascade setting, then you have to handle the deletes yourself.
My suggestion is to keep track of the deletes in a collection and do not issue NHibernate Deletes until the data is validated. That is, create MarkForDeletion methods for parent and child objects. When the user clicks delete, these methods add the object to a collection.
When the user is ready to commit the transaction, loop through the child objects that have been marked for deletion, remove them from the parent's children collection, and set their reference to parent to null. Then loop through the parent objects that are marked for deletion and validate that their children collection is empty.
If the data is valid, you can then delete the parent objects and let the cascade setting (all or all-delete-orphan) take care of the child records.