【问题标题】:How to delete child object in NHibernate?如何在 NHibernate 中删除子对象?
【发布时间】:2010-09-23 02:18:00
【问题描述】:

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

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

【问题讨论】:

    标签: nhibernate


    【解决方案1】:

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

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

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

    【讨论】:

    • 只是为了澄清-我现在只有在 Parent 对象上定义的关系。我试图将该对象上的级联设置为“全部”和“全部删除孤儿”,两次结果相同。你的意思是我还需要在子对象上定义多对一关系?
    • 在这种情况下 inverse="true" 属于父对象还是子对象?
    • 它属于不持有外键的类...通常是父类。
    • 感谢您的解释,我又遇到了一个逆向问题,看到它这样解释真的很有帮助。
    • 这确实有助于解决我遇到的问题。谢谢。
    【解决方案2】:

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

    Message 有很多 MessageSentTo:

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

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

    【讨论】:

      【解决方案3】:

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

      【讨论】:

        【解决方案4】:

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

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

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

        希望对你有帮助

        【讨论】:

        • 这需要另一个存储库。
        【解决方案5】:

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

        【讨论】:

        • 试过这个。我仍然遇到同样的异常。
        • all-delete-orphan 在删除父级时删除子级。这与删除这个家伙问的孩子没有任何关系。
        【解决方案6】:

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

        【讨论】:

        • 好的,我在子对象的映射中将列设置为 not-null="true"。因此,我在子对象的 IList 上调用 clear() 方法,然后尝试 SaveOrUpdate()。我仍然收到“无法将值 NULL 插入列”错误。我做错了什么吗?
        • 哪一列被抛出的错误?你究竟是如何删除模型中的孩子的?
        • 我在父对象的 Ilist 子对象上调用 clear() 方法。然后我在父级上调用 SaveOrUpdate()。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-11-25
        • 1970-01-01
        相关资源
        最近更新 更多