正如标题所说,基本上我想做的就是改变一个孩子的父母。但是当我尝试这样做时,我得到了异常" ObjectDeletedException:删除的对象将通过级联重新保存(从关联中删除已删除的对象)"。
我现在谷歌搜索了几个小时,但我找到的解决方案都没有为我工作!!
这些是我的课程:
public class Parent: Entity
{
public virtual IList<Child> Children { get; set; }
}
public class Child: Entity
{
public virtual DateTime? CancellationDate { get; set; }
}
类Entity是具有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()
抛出了上面的异常。
我想问题是因为Child改变了他的父级,因为级联NHibernate必须消除Child,但是之后它已被重新设置为另一个父级,所以,再次因为级联,它将不得不重新保存孩子。
我已经尝试更改映射,并将Child从前父集合中移除(在我将其分配给另一个父级之前或之后),但这些都不起作用......
任何帮助都将非常感谢!!
谢谢!
答案 0 :(得分:0)
我已经看到了你的免责声明: ...我一直在谷歌搜索几个小时,但我找到的解决方案都没有为我工作!!
但总的来说,上面的示例只是从不能够(重新)生成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();
}
...
这个测试正在通过。
那么问题出在哪里?只是在你没有显示的代码中的somwhere。有关此类问题的详细说明,请访问:
还有一些讨论和更多提示
ObjectDeletedException
(“已删除的对象将被重新保存...”)几乎总是意味着:某些对象已被删除。这是存储在当前session
中的信息。但仍有一些集合引用它......
答案 1 :(得分:0)
某种程度上我无法访问我提出问题的帐户。
事实证明,我们不会在逻辑上删除数据,因此将级联更改为“save-update”可以解决问题。
这个链接非常清楚地解释了NHibernate中重新定位的问题:
答案 2 :(得分:0)
我知道它已经有一段时间了,我不知道你是否仍然需要这个,但我最近遇到了这个问题,这里有一个对我有用的代码片段:
parent.Children.Remove(child);
session.Delete(child);
session.Evict(child);
child.ID = 0;
child.Parent = otherParent;
otherParent.Children.Add(child);
基本上,这会删除旧子项并添加一个全新的ID,并为另一个父项添加相同的属性。这可以防止您必须创建子对象的深层副本以将其添加到新父对象。它正在做的是取消孩子与其旧父母的关联,删除它(从会话),驱逐它(迫使nhibernate忘记对象的存在),重置ID(假设你使用sql种子身份列),重新养育它然后将其添加到新父母的集合中。
使用这种策略,我仍然可以在父映射上保留“cascade-all-delete-orphan”,而不必使关系“反向”。希望这有助于任何人解决这个问题,这可能是一个真正的痛苦......