I'm seeing behavior in Hibernate (3.6.10) that doesn't match my mental model of what should be happening, and I'd like to know if this means there's a bug, there was a conscious decision made to break from the (otherwise-valid) mental model, or my mental model is wrong.
I have a bi-directional OneToMany/ManyToOne relationship between Parent and Child, where Parent has many Children and Child is the owner of the relationship:
@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;
}
And my test (in an @Transactional JUnit test with the SpringJunit4ClassRunner):
@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);
}
My mental model says that changes to the relationship between Parent and Child get persisted by modifying the Child's Parent entity reference and saving the Child; changes to the Child's children collection are ignored by Hibernate.
Yet if I create new (transient) Child objects and add them to a detached Parent object, when I call sessionFactory.merge(parent)
, the merge()
call appears to inspect the Parent's children
collection and reject the merge because those children are transient, even though my code will be iterating through the children as soon as the merge()
call returns. (I get the same behavior with a new Parent object whose natural key matches one already in the database.)
Java Persistence With Hibernate has a single bullet that relates to this question (from the bottom of p. 413 of the 2007 corrected fifth edition): "Merging includes all value-typed properties and all additions and removals of elements to any collection." If the statement was "to any non-inverse collection", that would match my mental model (i.e. persist all changes that would be persisted by saveOrUpdate()
), but the inclusion of inverse collections in the word "any" conflicts with my mental model.
Can anyone explain why merge()
is considering the state of objects in an inverse Collection (one using mappedBy
), even though saveOrUpdate()
will ignore them? And is there any setting that would instruct merge()
to ignore those entities?
NOTE: This question is not the same as JPA2 and hibernate - why does merge store child entities whilst persist does not? (though the titles sound exactly the same), because that author is trying to cascade (and having it not happen with persist()
) whereas I do not want automatic cascading behavior.