如何在NHibernate中删除子对象?


79

我有一个父对象,它与子对象的IList具有一对多的关系。删除子对象的最佳方法是什么?我没有删除父母。我的父对象包含子对象的IList。这是一对多关系的映射:

<bag name="Tiers" cascade="all">
  <key column="mismatch_id_no" />
  <one-to-many class="TGR_BL.PromoTier,TGR_BL"/>
</bag>

如果我尝试使用clear()从集合中删除所有对象,然后调用SaveOrUpdate(),则会出现此异常:

System.Data.SqlClient.SqlException: Cannot insert the value NULL into column

如果我尝试分别删除子对象,然后将它们从父对象中删除,则会出现异常:

deleted object would be re-saved by cascade

这是我第一次处理在NHibernate中删除子对象。我究竟做错了什么?

编辑:只是为了澄清-我不是要删除父对象,只是子对象。我与父母建立了一对多的关系。我还需要在子对象映射上创建多对一关系吗?

Answers:


139

之所以会出现第一个错误,是因为从集合中删除项目时,NHibernate的默认操作模式是简单地断开关联。在数据库中,NHibernate尝试将子行上的外键列设置为null。由于不允许在该列中使用null,因此SQL Server会引发错误。清除集合不一定会删除子对象,但是一种删除方法是设置cascade = all-delete-orphan。这通知NHibernate应该删除新的孤立行,而不是设置外键列。

您收到第二个错误,因为在您调用SaveOrUpdate时,NHibernate首先删除了所有子对象。然后,由于两个关系都未标记为反向,因此NHibernate还将尝试将子表中的外键列设置为null。由于行已被删除,您将收到第二个错误。您需要在关系的一侧设置inverse = true才能解决此问题。通常在一侧(主键或父级)完成此操作。如果您不这样做,则NHibernate将为关系的各个方面进行适当的更新。不幸的是,运行两个更新不是适当的事情。

您应始终将关系的一侧标记为反面。根据您的编码方式,您可能需要也可能不需要使用级联。如果要在尝试使用Clear()时利用一次删除的优势,则需要定义级联。


只是为了澄清-我现在仅在Parent对象上定义了关系。我尝试将该对象上的级联设置为“所有”和“所有删除孤立”,两次都相同。您是说我还需要在子对象上定义多对一关系吗?
Mark Struzinski

在这种情况下,inverse =“ true”是否属于父对象或子对象?
Mark Struzinski

3
它属于不持有外键的类……通常是父类。
pmlarocque

谢谢您的解释,再次出现了一个反问题,这让我很高兴,看到这样解释确实很有帮助。
Mark Dickinson

这确实有助于解决我遇到的问题。谢谢。
罗宾·罗宾逊

3

根据Chuck的回答,我通过在父侧映射中添加Inverse = true解决了我的问题:

邮件有许多MessageSentTo:

[HasMany(typeof(MessageSentTo), Cascade = ManyRelationCascadeEnum.AllDeleteOrphan, Inverse = true)]
public IList<MessageSentTo> MessageSendTos
{
    get { return m_MessageSendTo; }
    set { m_MessageSendTo = value; }
}

我正在使用Castle ActiveRecord。谢谢查克。


2

尝试使用merge()而不是saveOrUpdate()。此外,请确保您的级联设置为all-delete-orphan,并且您的父子关系是可逆的(在父级上为inverse = true,然后在子级中的字段为parent-id,其中not-null = true) 。


2

在我们的示例中,我们有许多产品的类别,其中产品不可为空。

您可以通过以下方法来解决此问题:删除产品,并在冲洗前从家长的收藏中删除产品,但我们仍在寻找更好的解决方案。

product = pRepo.GetByID(newProduct.ProductID);
product.Category.Products.Remove(product);
pRepo.Delete(product);

希望它能有所帮助


1
但是,这需要另一个存储库。
2010年

0

将级联属性值从“ all”更改为“ all-delete-orphan”。


试过这个。我仍然遇到同样的异常。
Mark Struzinski

16
当删除父级时,all-delete-orphan会删除子级。这与删除像这个家伙问的孩子一样没有关系。
凯尔·西

-3

在导致问题的列上的映射中设置Not-Null = true。我不确定确切的语法(抱歉)。


好的,我在子对象的映射上将列设置为not-null =“ true”。因此,我在子对象的IList上调用clear()方法,然后尝试SaveOrUpdate()。我仍然收到“无法将值NULL插入列”错误。我在做别的事情吗?
Mark Struzinski

错误被抛出在哪一列?您究竟如何删除模型中的子级?
凯尔·西

我在父对象的Ilist子对象上调用clear()方法。然后,我在父级上调用SaveOrUpdate()。
Mark Struzinski
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.