c# - 多对多在 NHibernate 中删除具有共同关联的两个 parent

标签 c# nhibernate many-to-many cascade

我的应用中有 3 个顶级实体:Circuit、Issue、Document

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

当我删除一个 Circuit 时,我希望它删除与其关联的文档,除非它被其他东西使用。我希望 Issues 也有同样的行为。当唯一的关联在数据库中的同一个表中时,我让它工作,但如果它在另一个表中,那么它会由于外键约束而失败。

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

ex 2(这将正确地级联,因为从 Circuit 到 Document 只有外部约束。)
Document1 存在。
Circuit1 存在并包含对 Document1 的引用。
Circuit2 存在并包含对 Document1 的引用。
如果我删除 Circuit1,那么它会被删除,但 Document1 不会被删除,因为 Circuit2 存在。
如果我随后删除 Circuit2,则 Document1 将被删除。

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

数据库:
这认为不会让上传图像,所以这里是数据库的 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();
}

最佳答案

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

  1. 如果父集合中仍引用子集合,则将其删除。
  2. 如果子项不再在父项集合中引用,那么如果它是孤儿,即没有其他引用,则将其删除。

我认为这会按预期工作:

    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();
    }

关于c# - 多对多在 NHibernate 中删除具有共同关联的两个 parent ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4521229/

相关文章:

mysql、SQL、触发器、多对多

nhibernate - 如何自动删除多对多关联(级联)

c# - 在 Windows 7 事件日志中,什么是 "Source"?

c# - MVVM Light Messenger 类

c# - T-Sql 选择并将许多行和列连接成一行和一列

c# - 如何在 NHibernate 中映射 Collection<T>?

.net - 如何使用SQL Server 2005在NHibernate中映射uint

nhibernate - Fluent NHibernate 表命名约定不起作用

c# - Func<T, TResult> 访问参数

MySQL:如果连接表中的列包含 x,则选择具有相同 ID 的所有行