2010-12-23 55 views
3

兩個親我在我的應用程序3個頂層實體:電路,發行,文檔多對多刪除在NHibernate的共同協會

電路可以包含文檔和發佈可能包含的文檔。

當我刪除一個電路時,我希望它刪除與它關聯的文檔,除非它被別的東西使用。我希望與問題具有相同的行爲。我有它的工作時唯一的關聯是在同一個表中的數據庫,但如果它在另一個表中,然後由於外鍵約束失敗。

前1(這將正常級聯,因爲只有從電路外國約束到文檔
文檔1存在。
Circuit1存在幷包含對Document1的引用。
如果我刪除Circuit1,那麼它將刪除Document1。

前2(這將正常級聯,因爲只有從電路外國約束文檔。
文檔1存在。
Circuit1存在幷包含對Document1的引用。
Circuit2存在幷包含對Document1的引用。
如果我刪除Circuit1,那麼它將被刪除,但Document1不會被刪除,因爲Circuit2存在。
如果我然後刪除Circuit2,則Document1被刪除。

ex 3(這會引發錯誤,因爲當它刪除電路時,看到沒有其他電路引用文檔,因此它會嘗試刪除文檔,但不應該,因爲存在問題對文檔有外部約束
存在文檔1。
Circuit1存在幷包含對Document1的引用。
問題1存在幷包含對Document1的引用。
如果我刪除Circuit1,那麼它會失敗,因爲它試圖刪除Document1,但Issues1仍然有一個參考。

DB:
想到這不會讓上傳圖片,所以這裏是ERD的DB: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(); 
} 

回答

0

您需要在刪除父項之前清除集合。 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(); 
    } 
+0

添加的行: item.Documents.Clear(); 實際上不會導致行爲上的差異。問題不在於在處理單個實體時線路沒有正確刪除。問題是與文檔實體有關係的第二個實體仍然持有引用。該建議遭受與我提供的樣本相同的問題。 – 2010-12-24 19:47:38