正如标题所说,基本上我想做的是改变孩子的父母。但是当我尝试这样做时,我得到异常"对象删除异常:删除的对象将被级联重新保存(从关联中删除已删除的对象)"。
我已经在谷歌上搜索了几个小时,但我找到的解决方案都不适合我!!
这些是我参与的课程:
public class Parent: Entity
{
public virtual IList<Child> Children { get; set; }
}
public class Child: Entity
{
public virtual DateTime? CancellationDate { get; set; }
}
类实体是具有 Id 属性的实体。
这是父级的映射(Parents.hbm.xml):
<bag name="Children" cascade="all-delete-orphan" table="Schema.Child" where="CancellationDate is null">
<key column="ParentID"/>
<one-to-many class="Namespace.Child"/>
</bag>
这是我尝试将孩子重新分配给另一个父母的代码段:
foreach(Child c in Parent1.Children)
{
Parent2.Children.Add(c);
}
但是,session.Flush()
抛出上面的异常。我猜问题在于,既然孩子换了父母,因为级联,NHibernate将不得不消灭孩子,但后来它又被重新分配给了父级,所以,再次因为级联,它将不得不重新拯救孩子。
我已经尝试更改映射,并从前父级的集合中删除 Child(在我将其分配给另一个父级之前或之后),但这些都不起作用......
任何帮助将不胜感激!!
谢谢!!
我看到了你的免责声明:...我已经在谷歌上搜索了几个小时,但我找到的解决方案都不适合我!!
但总的来说,上面的例子根本无法(重新)产生ObjectDeletedException
。
在 nhibernate 中甚至还有一个内置测试,它检查:
NHibernate.Test.NHSpecificTest.NH1531 SampleTest ReparentingShouldNotFail
[Test]
public void ReparentingShouldNotFail()
{
FillDb();
using ( ISession session = OpenSession() )
{
var parent1 = session.Get<Parent>(1);
var parent2 = session.Get<Parent>(2);
Assert.AreEqual(1, parent1.Children.Count);
Assert.AreEqual(0, parent2.Children.Count);
Child p1Child = parent1.Children[0];
Assert.IsNotNull(p1Child);
parent1.DetachAllChildren();
parent2.AttachNewChild(p1Child);
session.Update(parent1);
session.Update(parent2);
// NHibernate.ObjectDeletedException :
// deleted object would be re-saved by cascade
// (remove deleted object from associations)
// [NHibernate.Test.NHSpecificTest.NH1531.Child#0]
session.Flush();
}
...
此测试已通过。
那么,问题出在哪里呢?只是在你没有显示的代码中。可以在此处找到此类问题的详细说明:
- NHibernate删除的对象将通过级联重新保存
这里还有一些讨论和更多提示
- NHibernate:删除的对象将通过级联重新保存。替换对象并删除旧对象
ObjectDeletedException
("删除的对象将被重新保存...")几乎总是意味着:某个对象被删除了。即存储在当前session
中的信息。但是仍然有一些集合引用它...
不知何故,我无法访问我提出问题的帐户。
事实证明,我们不会在物理上擦除数据,只是在逻辑上,因此将级联更改为"保存-更新"解决了这个问题。
这个链接非常清楚地解释了NHibernate中重新设置父级的问题:
http://osdir.com/ml/nhusers/2009-09/msg00323.html
已经有一段时间了,我不知道你是否还需要这个,但我最近遇到了这个问题,这里有一个对我有用的代码片段:
parent.Children.Remove(child);
session.Delete(child);
session.Evict(child);
child.ID = 0;
child.Parent = otherParent;
otherParent.Children.Add(child);
基本上,这会删除旧子项,并将具有新 ID 和相同属性的全新子项添加到另一个父项。 这样,您就不必创建子对象的深层副本来将其添加到新的父对象。 它所做的是解除子项与其旧父项的关联,将其删除(从会话中删除),逐出它(强制 nhibernate 忘记对象的存在),重置 ID(假设您使用的是 sql 种子身份列),重新设置其父级,然后将其添加到新父级的集合中。
使用这种策略,我仍然能够在父映射上保留"级联所有删除孤立",而不必使关系"反向"。 希望这对任何遇到这个问题的人都有帮助,这可能是一个真正的痛苦......