如何删除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(),我得到这个exception:
System.Data.SqlClient.SqlException: Cannot insert the value NULL into column
如果我尝试单独删除子对象然后将其从父项中删除,我得到一个exception:
deleted object would be re-saved by cascade
这是我第一次处理在NHibernate中删除子对象。 我究竟做错了什么?
编辑:只是为了澄清 – 我不是试图删除父对象,只是子对象。 我把这种关系build立在父母之间。 我是否也需要在子对象映射上创build多对一的关系?
你正在得到第一个错误,因为当你从集合中移除项目时,NHibernate的默认操作模式是简单地破坏关联。 在数据库中,NHibernate试图将子行上的外键列设置为null。 由于您不允许在该列中出现空值,因此SQL Server会引发错误。 清除集合不一定会删除子对象,但一种方式是设置cascade = all-delete-orphan。 这通知NHibernate它应该删除新的孤行,而不是设置外键列。
你会得到第二个错误,因为当你调用SaveOrUpdate时,NHibernate会首先删除所有的子对象。 然后,因为这两个关系都没有被标记为反向,所以NHibernate也尝试将子表中的外键列设置为null。 由于行已被删除,您将收到第二个错误。 你需要在关系的一边设置inverse = true来解决这个问题。 这通常在一个(主键或父)一侧完成。 如果你不这样做,NHibernate将为关系的每一方做适当的更新。 不幸的是,运行两个更新不是合适的事情。
你应该始终把你的关系的一面标记为反面。 根据你的代码,你可能需要也可能不需要使用级联。 如果您想要利用一次性删除操作来删除正在尝试使用Clear()的操作,则需要定义级联。
根据查克的回答,我已经解决了我的问题,通过在父面映射中添加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。 谢谢查克。
尝试使用merge()而不是saveOrUpdate()。 此外,请确保您的级联设置为all-delete-orphan,并且您的父 – 子关系是可逆的(对于父级,inverse = true,然后是具有not-null = true的父级id中的字段) 。
在我们的例子中,我们有许多产品的类别,其中产品是不可空的。
您可以通过删除产品并在冲洗前从父级集合中删除产品来解决此问题,但我们仍在寻找更好的解决scheme。
product = pRepo.GetByID(newProduct.ProductID); product.Category.Products.Remove(product); pRepo.Delete(product);
无论如何希望它有帮助
将级联属性值从“all”更改为“all-delete-orphan”。
在导致问题的列的映射中设置Not-Null = true。 我不确定确切的语法(对不起)。