Andy
Andy

Reputation: 21

collection was not processed by flush()

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

Answers (2)

prashant.kr.mod
prashant.kr.mod

Reputation: 1692

for my case, I resolved it in the following way:

@PersistenceContext(type = PersistenceContextType.EXTENDED)
  private EntityManager entityManager;

Upvotes: 0

Puneetsri
Puneetsri

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

Related Questions