为什么merge()尝试在反向@OneToMany集合中持久化/验证实体?

时间:2015-03-26 16:01:27

标签: hibernate jpa orm merge one-to-many

我看到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()),而我不想要自动级联行为。

1 个答案:

答案 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之间的某个版本中得到修复。