如何在NHibernate中删除子对象?

时间:2008-11-19 17:33:16

标签: nhibernate

我有一个父对象,它与子对象的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中删除子对象。我做错了什么?

编辑:只是为了澄清 - 我不是试图删除父对象,而只是删除子对象。我将父母的关系设置为一对多。我是否还需要在子对象映射上创建多对一关系?

6 个答案:

答案 0 :(得分:135)

您收到第一个错误,因为当您从集合中删除项目时,NHibernate的默认操作模式是简单地破坏关联。在数据库中,NHibernate尝试将子行上的外键列设置为null。由于您不允许该列中的空值,因此SQL Server会引发错误。清除集合不一定会删除子对象,但一种方法是设置cascade = all-delete-orphan。这告诉NHibernate它应该删除新的孤立行而不是设置外键列。

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

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

答案 1 :(得分: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。谢谢Chuck。

答案 2 :(得分:2)

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

答案 3 :(得分:2)

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

您可以通过删除产品并在刷新之前将其从父级的集合中删除来解决此问题,但我们仍在寻找更好的解决方案。

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

希望无论如何都有帮助

答案 4 :(得分:0)

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

答案 5 :(得分:-3)

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