很多人在NHibernate中删除了两个具有共同关联的父母

时间:2010-12-23 17:57:52

标签: c# nhibernate many-to-many cascade

我的应用中有3个顶级实体:电路,问题,文档

电路可以包含文档,问题可以包含文档。

当我删除一个电路时,我希望它删除与之相关的文档,除非它被其他东西使用。我希望问题与此相同。当唯一的关联在db中的同一个表中时,我有它工作,但如果它在另一个表中,那么它会因外键约束而失败。

ex 1(这将正确级联,因为从电路到文档只有外来约束
Document1存在。
Circuit1存在并包含对Document1的引用 如果我删除Circuit1,那么它会删除Document1。

ex 2(这将正确级联,因为从电路到文档只有外来约束。
Document1存在。
Circuit1存在并包含对Document1的引用 Circuit2存在并包含对Document1的引用 如果删除Circuit1,则删除它,但不删除Document1,因为Circuit2存在 如果我然后删除Circuit2,则删除Document1。

ex 3(这将引发错误,因为当它删除电路时,它看到没有其他电路引用该文档,因此它试图删除该文档。但它不应该,因为有一个对文档有外来约束的问题。
文件1存在。
Circuit1存在并包含对Document1的引用 Issue1存在并包含对Document1的引用 如果我删除Circuit1,那么它会失败,因为它试图删除Document1,但Issues1仍然有一个引用。

DB:
这个想法不会让上传图像,所以这里是数据库的ERD:http://lh3.ggpht.com/_jZWhe7NXay8/TROJhOd7qlI/AAAAAAAAAGU/rkni3oEANvc/CircuitIssues.gif

型号:

public class Circuit
{
    public virtual int CircuitID { get; set; }
    public virtual string CJON { get; set; }
    public virtual IList<Document> Documents { get; set; }
}
public class Issue
{
    public virtual int IssueID { get; set; }
    public virtual string Summary { get; set; }
    public virtual IList<Model.Document> Documents { get; set; }
}
public class Document
{
    public virtual int DocumentID { get; set; }
    public virtual string Data { get; set; }
}

映射文件:

<?xml version="1.0" encoding="utf-8"?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" namespace="Model" assembly="Model">
  <class name="Circuit" table="Circuit">
    <id name="CircuitID">
      <column name="CircuitID" not-null="true"/>
      <generator class="identity" />
    </id>
    <property name="CJON" column="CJON" type="string" not-null="true"/>
    <bag name="Documents" table="CircuitDocument" cascade="save-update,delete-orphan">
      <key column="CircuitID"/>
      <many-to-many class="Document">
        <column name="DocumentID" not-null="true"/>
      </many-to-many>
    </bag>
  </class>
</hibernate-mapping>
<?xml version="1.0" encoding="utf-8"?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" namespace="Model" assembly="Model">
  <class name="Issue" table="Issue">
    <id name="IssueID">
      <column name="IssueID" not-null="true"/>
      <generator class="identity" />
    </id>
    <property name="Summary" column="Summary" type="string" not-null="true"/>
    <bag name="Documents" table="IssueDocument" cascade="save-update,delete-orphan">
      <key column="IssueID"/>
      <many-to-many class="Document">
        <column name="DocumentID" not-null="true"/>
      </many-to-many>
    </bag>
  </class>
</hibernate-mapping>
<?xml version="1.0" encoding="utf-8"?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" namespace="Model" assembly="Model">
  <class name="Document" table="Document">
    <id name="DocumentID">
      <column name="DocumentID" not-null="true"/>
      <generator class="identity" />
    </id>
    <property name="Data" column="Data" type="string" not-null="true"/>
  </class>
</hibernate-mapping>

代码:

using (ISession session = sessionFactory.OpenSession())
{
    var doc = new Model.Document() { Data = "Doc" };

    var circuit = new Model.Circuit() { CJON = "circ" };
    circuit.Documents = new List<Model.Document>(new Model.Document[] { doc });

    var issue = new Model.Issue() { Summary = "iss" };
    issue.Documents = new List<Model.Document>(new Model.Document[] { doc });

    session.Save(circuit);
    session.Save(issue);
    session.Flush();                
}
using (ISession session = sessionFactory.OpenSession())
{
    foreach (var item in session.CreateCriteria<Model.Circuit>().List<Model.Circuit>())
    {
        session.Delete(item);
    }
    //this flush fails, because there is a reference to a child document from issue
    session.Flush();
    foreach (var item in session.CreateCriteria<Model.Issue>().List<Model.Issue>())
    {
        session.Delete(item);
    }
    session.Flush();
}

1 个答案:

答案 0 :(得分:0)

您需要在删除父级之前清除该集合。 delete-orphan导致删除操作级联到子级,因为子级仍在集合中引用。在取消对象之前,该对象不具有成为孤儿的可能性,因此不会检查该对象。 Section 10.11 in this documentation解释得很好,但仍然令人困惑。据我了解,删除父项时delete-orphan有两种可能的结果:

  1. 如果孩子仍然在父母的集合中被引用,那么它将被删除。
  2. 如果在父集合中不再引用该子节点,则如果它是孤儿则将其删除,即没有其他引用。
  3. 我认为这会按预期运作:

        using (ISession session = sessionFactory.OpenSession())
        {
            foreach (var item in session.CreateCriteria<Model.Circuit>().List<Model.Circuit>())
            {
                item.Documents.Clear();
                session.Delete(item);
            }
            session.Flush();
            foreach (var item in session.CreateCriteria<Model.Issue>().List<Model.Issue>())
            {
                item.Documents.Clear();
                session.Delete(item);
            }
            session.Flush();
        }