2014-01-31 71 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)确保相关关系始终被移除,无需任何进一步的工作。