我的模型看起来像这样(在实际情况下有吸气剂和制定者):
class Foo {
Set<Bar> bars;
void attachBars(Set<Bar> bars){
this.bars = bars;
for(Bar bar : bars)
bar.foo = this;
}
}
class Bar {
Set<Baz> bazes;
}
class Baz {
}
然后我执行:
Foo foo = e.find(Foo.class, "id");
Hibernate.initialize(foo.bars);
em.detach(foo)
Foo foo2 = e.find(Foo.class, "id");
doSomeChanges(foo2);
foo2.attachBars(foo.bars);
我在调试器中看到的内容:
在attachBars(foo.bars);
之前 bar.bazes
LazyInitializationException
字段
将attachBars(foo.bars);
bar.bazes
个字段设置为null后,在em.merge之后,将从数据库中删除bazes。
答案 0 :(得分:0)
attachBars
方法永远不应更改对this.bars的引用。它将被 Hibernate 实例化,因为我们通过find()
,即Hibernate会话来重新获取foo。引用此集合是必不可少的,因为只有这样我们才能依赖正确的脏检查(新添加,删除的项目)
所以它应该是这样的(期望集合由Hibernate实例化):
void attachBars(Set<Bar> bars){
if(this.bars == null){
this.bars = new HashSet<Bar>();
}
for(Bar bar : bars){
this.bars.add(bar);
bar.foo = this;
}
}
但在这种情况下,这还不够。传递的colleciton bars
来自分离的对象。其中没有填充bazes
集合。
一旦将它们重新分配到刚刚加载的对象,它们似乎就有了空集合。因此,在我们分离根对象之前,我们应该强制所有Baz实例的初始化。
更好的解决方案,我建议迭代旧的条形集合并通过id加载实际的代理