Question

Within a complex usertransction (ut) we have to find a JPA entity, add a new child and find the parent entity again. We observe, that the list of children is incomplete when we fetch the parent inside the transaction and complete as expected after the transaction commits. Everything is single threaded and uses the same entity manager instance.

Are we missing something obvious that would explain that behaviour?

ut.begin();

// find the parent entity
ParentEntity parent = em.find(parentKey);
assertEquals(parent.getChildren().size(), 1);   // as expected

// add one child
ChildEntity child = createChild();        // create child for the parent
child.setParentRef(parent.getRef());
em.persist(child);
em.flush();

// find the parent entity again
ParentEntity parent = em.find(parentKey);
assertEquals(parent.getChildren().size(), 1);   // UNEXPECTED! Should be two...

ut.commit();

// find the parent entity again
ParentEntity parent = em.find(parentKey);

assertEquals(parent.getChildren().size(), 2);   // now I see 2 children. After committing

The the relation on parent is defined like:

@OneToMany(orphanRemoval=true, cascade=CascadeType.ALL, fetch=FetchType.LAZY)
@JoinColumn(name="parent_ref", referencedColumnName="ref")
List<ChildEntity> children = new ArrayList<ChildEntity>();
Was it helpful?

Solution

This is completely expected. You set the parent of the child, but didn't add the child to the parent list. And all is in a single transaction, so the parent returned by the second call to em.find(parentKey) comes directly from the first-level cache and is thus the exact same object as the one returned by the first call.

It's your responsibility to maintain the coherence of the object graph in a transaction. See http://docs.jboss.org/hibernate/core/4.3/manual/en-US/html_single/#tutorial-associations-usingbidir

OTHER TIPS

You need to add new child to the parent collection:

ChildEntity child = createChild();
child.setParentRef(parent.getRef());
parent.getChildren().add(child);
em.persist(parent);
em.persist(child); // only required if the persist does not cascade to children
em.flush();
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top