为什么 merge() 会尝试 persist/validate 逆@OneToMany collection 中的实体?
Why does merge() attempt to persist/validate entities in an inverse @OneToMany collection?
我在 Hibernate (3.6.10) 中看到的行为与我对应该发生的事情的心智模型不符,我想知道这是否意味着存在错误,是有意识的决定打破了(otherwise-valid)的心智模型,或者我的心智模型是错误的。
我在 Parent 和 Child 之间有一个 bi-directional OneToMany/ManyToOne 关系,其中 Parent 有很多 Children 和 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 的 Parent 实体引用并保存 Child; Child 的 children collection 的更改被 Hibernate 忽略。
然而,如果我创建新的(瞬态)Child objects 并将它们添加到分离的 Parent object,当我调用 sessionFactory.merge(parent)
时, merge()
调用似乎检查了 Parent 的 children
collection 并拒绝合并,因为那些 children 是暂时的,即使我的代码将迭代children 一旦 merge()
调用 returns。 (我用一个新的 Parent object 得到了相同的行为,它的自然键与数据库中已有的键匹配。)
Java Persistence With Hibernate 有一个项目符号与这个问题相关(来自 2007 年修正后的第五版第 413 页的底部):"Merging includes all value-typed properties and all additions and removals of elements to any collection." 如果语句是 "to any non-inverse collection",这将符合我的心智模型(即保留 saveOrUpdate()
会保留的所有更改),但在单词 "any" 中包含反向 collection 与我的心智模型冲突.
任何人都可以解释为什么 merge()
正在考虑 object 的逆状态 Collection(一个使用 mappedBy
),即使 saveOrUpdate()
会不理他们吗?是否有任何设置可以指示 merge()
忽略这些实体?
注意: 这个问题与 JPA2 and hibernate - why does merge store child entities whilst persist does not? 不同(尽管标题听起来完全一样),因为作者正在 尝试 进行级联(并且 persist()
不会发生这种情况),而我不希望自动级联行为。
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.
我在 Hibernate (3.6.10) 中看到的行为与我对应该发生的事情的心智模型不符,我想知道这是否意味着存在错误,是有意识的决定打破了(otherwise-valid)的心智模型,或者我的心智模型是错误的。
我在 Parent 和 Child 之间有一个 bi-directional OneToMany/ManyToOne 关系,其中 Parent 有很多 Children 和 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 的 Parent 实体引用并保存 Child; Child 的 children collection 的更改被 Hibernate 忽略。
然而,如果我创建新的(瞬态)Child objects 并将它们添加到分离的 Parent object,当我调用 sessionFactory.merge(parent)
时, merge()
调用似乎检查了 Parent 的 children
collection 并拒绝合并,因为那些 children 是暂时的,即使我的代码将迭代children 一旦 merge()
调用 returns。 (我用一个新的 Parent object 得到了相同的行为,它的自然键与数据库中已有的键匹配。)
Java Persistence With Hibernate 有一个项目符号与这个问题相关(来自 2007 年修正后的第五版第 413 页的底部):"Merging includes all value-typed properties and all additions and removals of elements to any collection." 如果语句是 "to any non-inverse collection",这将符合我的心智模型(即保留 saveOrUpdate()
会保留的所有更改),但在单词 "any" 中包含反向 collection 与我的心智模型冲突.
任何人都可以解释为什么 merge()
正在考虑 object 的逆状态 Collection(一个使用 mappedBy
),即使 saveOrUpdate()
会不理他们吗?是否有任何设置可以指示 merge()
忽略这些实体?
注意: 这个问题与 JPA2 and hibernate - why does merge store child entities whilst persist does not? 不同(尽管标题听起来完全一样),因为作者正在 尝试 进行级联(并且 persist()
不会发生这种情况),而我不希望自动级联行为。
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.