2014-01-31 101 views
2

請幫我解決以下情況。我有三張桌牌Cardlist,Contact和多對多表ContactCardlist。我想刪除Cardlist中刪除記錄的多對多表ContactCardlist中的所有記錄。因此,我找到了所需的Cardlist,使用foreach來迭代「contactcardlists」 - 設置並使用session.Delete(ItemFromTheSet)刪除每條記錄。但在transaction.commit()之後,我得到一個異常,說我們不能用NULL更新列CardlistId(在表ContactCardlist中)。因此使用「更新」命令,而不是「刪除」命令。使用Nhibernate刪除父項後,刪除多對多表中的所有記錄

下面您可以找到Cardlist和ContactCardlist表的映射。

<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" namespace="XXXXX.Entities" assembly="XXXXX"> 
    <class name="ContactCardlist" table="ContactCardlist"> 
    <composite-id class="ContactsCardlistId" name="ContactsCardlistId" unsaved-value="any" > 
     <key-many-to-one name="cardlist" class="Cardlist" column="CardlistId" /> 
     <key-many-to-one name="contact" class="Contact" column="ContactId" /> 
    </composite-id> 
    </class> 
</hibernate-mapping> 

<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" namespace="XXXXXXXXX.Entities" assembly="XXXXXXXXXXXXXX"> 
    <class name="Cardlist" table="Cardlist"> 
     <id name="cardlistid" column="cardlistid" type="int"> 
      <generator class="native"/> 
     </id> 
     ....//lots of properties 

    <set name = "contactcardlists" cascade="none" order-by="ContactId"> 
     <key column ="cardlistid"/> 
     <one-to-many class="ContactCardlist" /> 
    </set>  
    </class> 
</hibernate-mapping> 

謝謝大家提前。

回答

2

您所遇到的是來自NHibernate ISession的本質。

  1. 我們做負載「父」 Cardlist,所以目前session知道這個對象,甚至關於其孩子
  2. 我們遍歷孩子,並要求session.Delete(child)(ItemFromTheSet)
  3. 最後session.Flush()被調用,並且NHibernates必須決定執行哪些SQL語句
  4. 全部子女,映射到父母,即將被刪除。從上面的映射,NHibernate明白,他們必須首先從<set name = "contactcardlists">集合中刪除。
  5. 更新,發行,chaning父<key column ="cardlistid"/>爲空

所以,這是發生了什麼事。我們如何解決它?首先,我們必須告知NHibernate,孩子完全瞭解其父母,並且可以自己管理。這是inverse="true"設置

<set name = "contactcardlists" inverse="true" 
    cascade="none" order-by="ContactId"> 
    <key column ="cardlistid"/> 
    <one-to-many class="ContactCardlist" /> 
</set> 

這將指示NHibernate的直接處理的孩子,只能發出DELETE語句。

級聯可能是下一個改進。因爲這將使我們能夠調用

parent.contactcardlists.Clear() 
session.Udpate(parent) 

和NHibernate將correclty問題DELETE語句。在這種情況下,映射應該是這樣的:

<set name = "contactcardlists" inverse="true" 
    cascade="all-delete-orphan" 
    order-by="ContactId"> 
    <key column ="cardlistid"/> 
    <one-to-many class="ContactCardlist" /> 
</set> 

最後,如果你能介紹一下Surrogated鍵進入配對錶ContactCardlist - ContactCardlistId,很多東西將被簡化。真的很多。孩子的映射,然後可能是:

<class name="ContactCardlist" table="ContactCardlist"> 
    <id column="ContactsCardlistId" name="Id" /> 

    <many-to-one name="cardlist" class="Cardlist" column="CardlistId" /> 
    <many-to-one name="contact" class="Contact" column="ContactId" /> 

</class> 

並與一個對象,它確實有Surrogated重點工作...是更容易

+0

對不起額外的問題:按照我的理解,我們可以只添加inverse =「true」表示集合的描述,並在foreach語句中使用Delete方法(沒有將屬性「cascade」從「None」更改爲「all-delete-orphan」)?你說「下一步改進」,據我所知,這不是一個強制性的改變。 – Max

+0

inverse =「true」*(你肯定應該谷歌它,以獲得更多的信息,請)*表示:NHibernate,這個集合是由元素構建的,他們能夠關心自己。如果一切都正確設置,這意味着,一旦這個項目從集合中刪除,NHibernate直接與此項目溝通:到DELETE。沒有反向... NHibernate不能確定,並且必須首先執行UPDATE ...以從子刪除引用,然後刪除... –

+0

非常感謝,我會將它谷歌它。 – Max

1

我不熟悉與NHibernate的,但你有沒有考慮兩種:

(一)建立了CardList和ContactCardlist(如果可能的話)之間OnDelete級聯關係,並設置在ContactCardlist外鍵索引確保效率。

OR使用原始ADO到具有 「DELETE FROM ContactCardlist WHERE Cardlistid = X」 刪除記錄

(b)中。 (a)選項簡單而有效。選項(b)比項目迭代更有效。

兩者都可以工作,但選項(a)確保相關關係始終被移除,無需任何進一步的工作。