开发者

Delete Parent and Child without cascade

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 S开发者_如何学JAVAomeParent 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).


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.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜