Issue with orphanRemoval and multiple EntityManagers

#1

Hi,

We have a problem where our database size grows over time more than expected. We've traced it down to the following issue:

I have some entities that are using OneToMany relationship with orphanRemoval set to true. I use a new EntityManager for each transaction (which normally happens in multithreaded application). When I create a child entity in one transaction and then remove it in another transaction, the database still contains 1 child entity. If I remove it and add another child entity, the database contains 3 child entities. If I use the same EntityManager for both transactions for these scenarios, the database contains 0 and 2 child entities respectively.

The expected result is 0 and 1 respectively, regardless of which entity manager is used.

The test case attached, I was using version 2.3.7_08.

Kind regards,

Natalia.

#2

Thank you for this report and for the test. Here is the same test in one class format and after omission of irrelevant elements (please use this format in your posts when possible):

import java.util.*;

import javax.persistence.*;


public class T740 {

    public static void main(String [] args){
        EntityManagerFactory emf =
            Persistence.createEntityManagerFactory(
                "objectdb:test.tmp;drop");
        long orgId = 0;
       
        Organisation newOrganisation = new Organisation();
        newOrganisation.addElectronicAddress(
            new ElectronicAddress("[email protected]"));

        EntityManager em = emf.createEntityManager();
        em.getTransaction().begin();               
        em.persist(newOrganisation);
        em.getTransaction().commit();
        orgId = newOrganisation.getId();
        em.close();
       
        em = emf.createEntityManager();
        Organisation originalOrganisation =
            em.find(Organisation.class, orgId);      
        originalOrganisation.getElectronicAddresses().clear();       
        originalOrganisation.addElectronicAddress(
            new ElectronicAddress("[email protected]"));
        em.getTransaction().begin();
        //em.merge(originalOrganisation);
        em.getTransaction().commit();

        TypedQuery<ElectronicAddress> q3 = em.createQuery(
            "select t from " + ElectronicAddress.class.getName() + " t",
            ElectronicAddress.class);
        List<ElectronicAddress> res3 = q3.getResultList();
       
        System.out.println("Number of addresses: "+res3.size());
        em.close();

        emf.close();
    }
   
    @Entity
    public static class Organisation {

        @Id
        private long id;

        @OneToMany(cascade=CascadeType.ALL, fetch=FetchType.EAGER, orphanRemoval=true)
        private List<ElectronicAddress> electronicAddresses =
            new ArrayList<ElectronicAddress>();

        public Organisation() {
            super();
        }

        public long getId() {
            return id;
        }

        public List<ElectronicAddress> getElectronicAddresses() {
            return electronicAddresses;
        }

        public void addElectronicAddress(ElectronicAddress electronicAddress) {
            electronicAddresses.add(electronicAddress);
        }
    }

    @Entity
    public static class ElectronicAddress  {
       
        private String address;
       
        public ElectronicAddress() {
        }
       
        public ElectronicAddress(String address) {
            this.address = address;
        }
    }
}

Your test demonstrated 2 issues:

  • Duplication of new objects during cascading merge - this is a known issue. You may subscribe to it, and until it is solved use workarounds (i.e. avoiding cascading merge to new objects). Actually in this test merge is not really needed so removing the merge solves the problem.
  • Detecting orphan objects in reflection mode. This is fixed now in build 2.3.7_13. Notice that the test works well also with previous builds when enhancement is used. So even though it is good that you reported the bug and it is now fixed, you should also verify that your application uses enhanced classes (which are much more efficient).
ObjectDB Support
#3

This test case has been distilled from very large amount of code, some of it not under our control. Refactoring all that code to remove cascading merge is not possible. When are you planning to fix the underlying issue?

Regarding using enhanced classes - we did try to use them, but it had it's own set of issues, so we moved back to plain version. Are you saying that you do not support using your DB without enchanced classes?

Regards,

Natalia.

#4

> When are you planning to fix the underlying issue?

Usually bugs are fixed immediately when found. This is one of a very few bugs that require more time to be fixed. It is unknown yet when it will be fixed but your subscription to it now may accelerate it.

> Are you saying that you do not support using your DB without enchanced classes?

No, it is supported of course. But since the 2 modes use separate code in many areas (e.g. detecting orphan entities) bugs are not identical. However, enhanced classes are much more efficient in performance and in memory consumption, so it is highly recommended to use only enhanced classes in production.

ObjectDB Support
#5

Build 2.3.7_18 fixes the cascading merge issue.

ObjectDB Support

Reply