Reputation: 21
I'm trying to remove child element from bidirectional association. My understating is that if I query Employee instance and then use getChildren()
method to fetch associated child, both parent and child records are managed. Now when I call child.setParent(null)
and parent.getChildren().remove(child)
both updates should be persisted when transaction commits, however I'm getting: org.hibernate.AssertionFailure: collection [org.rand.model.Employee.children] was not processed by flush()
exception unless I call merge on a child element or fetch children by query.
Can someone explain why is it happening?
I'm using hibernate 3.5.6-Final
Thanks
UPDATE: After a while of debugging I found the code that was causing this error and I must have accidently removed it while posting question. I sincerely apologize for that.
The culprit was custom OneToManyInverseCheck
bean validator that was verifying if relationship is set on both parent and child. This was triggering loading of additional entities (children of children) during commit operation.
Entity:
@Entity
public class Employee {
@Id
@GeneratedValue(strategy=GenerationType.TABLE)
private int id;
@Version
private int version;
private String name;
@ManyToOne
private Employee parent;
@OneToMany(mappedBy="parent")
@OneToManyInverseCheck(inverseFieldName="parent")
private List<Employee> children;
//get/set methods ommitted
}
Simple JUnit:
public class JPAUpdate {
private static EntityManagerFactory emf;
private EntityManager em;
@BeforeClass
public static void init() {
emf = Persistence.createEntityManagerFactory("myapp-db");
}
@Before
public void setUp() throws Exception {
em = emf.createEntityManager();
}
@Test
public void removeChildWithMerge() {
em.getTransaction().begin();
Employee e = em.createQuery("from Employee e where e.children is not empty order by e.id asc", Employee.class).getResultList().get(0);
Employee child = e.getChildren().get(0);
child.setParent(null);
e.getChildren().remove(child);
// removing this merge causes org.hibernate.AssertionFailure: collection [org.rand.model.Employee.children] was not processed by flush()
em.merge(child);
em.getTransaction().commit();
}
@Test
public void removeChildWithFetch() {
em.getTransaction().begin();
Employee e = em.createQuery("from Employee e left join fetch e.children where e.children is not empty order by e.id asc", Employee.class).getResultList().get(0);
Employee child = e.getChildren().get(0);
child.setParent(null);
e.getChildren().remove(child);
//em.merge(child); - no merge needed
em.getTransaction().commit();
}
@Test
public void removeChild() {
em.getTransaction().begin();
Employee e = em.createQuery("from Employee e left join fetch e.children where e.children is not empty order by e.id asc", Employee.class).getResultList().get(0);
Employee child = e.getChildren().get(0);
child.setParent(null);
e.getChildren().remove(child);
//em.merge(child); - no merge needed
em.getTransaction().commit();
}
}
Upvotes: 2
Views: 7534
Reputation: 1692
for my case, I resolved it in the following way:
@PersistenceContext(type = PersistenceContextType.EXTENDED)
private EntityManager entityManager;
Upvotes: 0
Reputation: 254
It could be because in removeChildWithMerge your children collection was lazy loaded and during flush, triggering loading of the items which result in this exception. You could have used Hibernate.inititalize(obj) instead of calling merge. On the other hand, in removeChildWithFetch, you are using fetch to eagerly load the collection and hence collection items.So during flush, item was already loaded so no issue.
Upvotes: 4