我看到Hibernate(3.6.10)中的行为与我应该发生的事情的心理模型不相符,我想知道这是否意味着在那里bug,有意识地决定打破(否则是有效的)心理模型,或者我的心理模型是错误的。
我在Parent和Child之间有一个双向的OneToMany / ManyToOne关系,其中Parent有很多Child,Child是该关系的所有者:
@Entity
public class Child {
@ManyToOne
@JoinColumn(name="PARENTID", nullable=false)
private Parent parent;
}
@Entity
public class Parent {
@OneToMany(mappedBy="parent", fetch=FetchType.LAZY)
private List<Child> children;
}
我的测试(在使用SpringJunit4ClassRunner的@Transactional JUnit测试中):
@Test
public void test() {
Child child = new Child();
child.setName("TEST");
childDao.saveOrUpdate(child);
childDao.getSession.flush();
childDao.getSession.evict(child);
Parent parent = new Parent();
parent.setChild(child);
child.addParent(parent);
childDao.merge(child);
}
我的心理模型说,通过修改Child的父实体引用并保存Child,可以保持父和子之间关系的更改; Hibernate会忽略对Child的子集合的更改。
然而,如果我创建新的(瞬态)Child对象并将它们添加到分离的Parent对象,当我调用sessionFactory.merge(parent)
时,merge()
调用似乎会检查父children
{{1}收集并拒绝合并,因为这些子项是瞬态的,即使我的代码将在merge()
调用返回后立即遍历子节点。 (我使用一个新的Parent对象得到了相同的行为,该对象的自然键与数据库中已有的自然键匹配。)
Java持久性Hibernate有一个与这个问题相关的子弹(来自2007年第5版的第413页底部):&#34;合并包括所有值类型属性以及元素的所有添加和删除任何收藏品。&#34;如果语句是&#34;对于任何非逆集合&#34;,那将匹配我的心理模型(即保留saveOrUpdate()
所持有的所有变化),但是在单词中包含反向集合&#34;任何&#34;与我的心理模型发生冲突。
有人可以解释为什么merge()
正在考虑反向集合中的对象状态(使用mappedBy
),即使saveOrUpdate()
会忽略它们吗?是否有任何设置可以指示merge()
忽略这些实体?
注意:此问题与JPA2 and hibernate - why does merge store child entities whilst persist does not?不同(虽然标题听起来完全相同),因为该作者尝试级联(和让它不会发生在persist()
),而我不想要自动级联行为。
答案 0 :(得分:1)
merge操作将传入的实体状态复制到附加实体或新加载的实体快照。
我添加了一个test on GitHub来复制你的Hibernate 4.3.8的说法,它运行得很好。反向忽略Child实体,简单地忽略瞬态实体。
两个瞬态实体:
doInTransaction(session -> {
Post _post = new Post("Post");
_post.getComments().add(new Comment());
session.persist(_post);
return _post;
});
和分离的:
final Post post = doInTransaction(session -> {
Post _post = new Post("Post");
session.persist(_post);
return _post;
});
doInTransaction(session -> {
post.getComments().add(new Comment());
session.merge(post);
});
已正确保存,反向方面将被忽略。
因为这在3.6.10下失败并且按照4.3.8的预期工作,所以很可能这只是Hibernate 3.6.10中的一个错误,它在3.6.10和4.3.8之间的某个版本中得到修复。