使用Nhibernate删除父项后删除多对多表中的所有记录

时间:2014-01-31 11:35:26

标签: c# sql-server nhibernate

请帮我解决以下情况。我有三张桌子Cardlist,Contact和多对多表ContactCardlist。我想在删除Cardlist中的记录时删除多对多表ContactCardlist中的所有记录。所以,我找到了所需的Cardlist,使用foreach迭代“contactcardlists”-set并使用session.Delete(ItemFromTheSet)删除每条记录。但是在transaction.commit()之后,我获得了一个异常,它说我们不能用NULL更新列CardlistId(在表ContactCardlist中)。因此使用“更新”命令,而不是“删除”一个。

您可以在下面找到表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 个答案:

答案 0 :(得分:2)

您所遇到的是来自NHibernate ISession的本质。

  1. 我们会加载“父级”Cardlist,因此当前session知道此对象,甚至是其子级
  2. 我们对孩子进行迭代并询问session.Delete(child) (ItemFromTheSet)
  3. 最后调用session.Flush(),NHibernates必须决定必须执行哪些SQL语句
  4. 即将删除映射到父级的所有子级。从上面的映射中,NHibernate理解,必须首先从<set name = "contactcardlists">集合中删除它们。
  5. 发布更新,将父<key column ="cardlistid"/>变为空
  6. 所以,这就是发生的事情。我们怎么解决呢?首先,我们必须通知NHibernate,孩子完全了解其父母,并且可以自我管理。这是inverse="true"设置

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

    这将指示NHibernate直接处理child,并仅发出DELETE语句。

    级联可能是下一个改进。因为那样我们就可以打电话了

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

    和NHibernate会发出相关的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键的对象...更容易

答案 1 :(得分:1)

我不熟悉NHibernate,但您考虑过:

(a)在CardList和ContactCardlist之间为OnDelete建立级联关系(如果可能),并在ContactCardlist中设置外键索引以确保效率。

OR

(b)使用原始ADO删除带有“DELETE FROM ContactCardlist WHERE Cardlistid = X”的记录。

选项(a)简单有效。选项(b)比项目迭代更有效。

要么可以工作,但选项(a)确保始终删除相关关系而无需任何进一步的工作。