ObjectDB ObjectDB

Items in list are doubled, when the entity class is not enhanced

#1

Dear all,

I have a problem with adding items (entities) into other entity list. When the classes are not enhanced, added items are doubled. Here is an example:


@Entity
public class Customer implements Serializable {
   
    private static final long serialVersionUID = 1L;

    @Id @GeneratedValue
    private Long id;
   
    @OneToMany(mappedBy = "customer",fetch= FetchType.EAGER,
               cascade= CascadeType.ALL,orphanRemoval=true)
    List
   
     itemList;

... getters and setters

}


@Entity
public class Item implements Serializable {
   
    private static final long serialVersionUID = 1L;

    @Id @GeneratedValue
    private Long id;
   
    @ManyToOne
    private Customer customer;

... getters and setters

}

public class JavaApplication {

    public static void main(String[] args) {
        EntityManagerFactory emf =
            Persistence.createEntityManagerFactory("$objectdb/db/Test.odb");
        EntityManager em = emf.createEntityManager();
      
        em.find(Customer.class, Customer.class);
        em.find(Item.class, Item.class);
       
        // delete all customers and items
        List l = em.createQuery("select c from Customer c").getResultList();
        em.getTransaction().begin();
        for(Object o : l){
            em.remove(o);
        }
        em.getTransaction().commit();
        l = em.createQuery("select i from Item i").getResultList();
        em.getTransaction().begin();
        for(Object o : l){
            em.remove(o);
        }
        em.getTransaction().commit();
       
        em.getTransaction().begin();
        Customer c = new Customer();
        em.persist(c);
        em.getTransaction().commit();
        em.refresh(c);
       
        em.getTransaction().begin();
        Item i = new Item();
        i.setCustomer(c);
        c.getItemList().add(i);
        em.merge(c);
        em.getTransaction().commit();
        em.refresh(c);
       
        System.out.println("Item count = "+c.getItemList().size());
       
        em.close();
        emf.close();
    }
}


   

The result is "Item count = 2". Is this another bug?

Michael

 

edit
delete
#2

I've found out a new thing - items are also doubled, when the classes are enhanced and before merging the customer object a field is setted.

Previous example can be used as a test case, only:

1. add enhancement, for example put "com.objectdb.Enhancer.enhance("javaapplication.*");" into the first line in main

2. add a String field into Customer with getters and setters. (the field name in my case is text)

3. before em.merge(c); add this line:

c.setText("");

 

Please, can someone fix this as fast as the previous bugs? Thank you

Michael

edit
delete
#3

Your program (in #1) demonstrates a very strange behavior, which is the result of the following:

  1. Invocation of merge on a managed Customer instance (which has never been detached).
  2. According to JPA - the merge operation is ignored for Customer - but cascaded to Item.
  3. Merging Item results in a new copy of the Item instance that becomes managed and stored in commit.
  4. The original Item remains non managed (new) until commit - but then is is persisted because of cascading from Customer.
  5. The result is 2 Item instances - the one that you have built and the one that was created by merge.

It is unclear yet what is the correct behavior and this will be further explored (in addition to the difference between using enhancement or not and the new info in your #2 update).

But meanwhile - maybe you can just avoid the unnecessary merge of an already managed entity object.

 

ObjectDB Support
edit
delete
#4

Even though the result is very strange - it seems that the behavior of ObjectDB in this case follows JPA.

Your update (#2) indicates that this is also how it works with enhancement - but the difference is that when using enhancement - an entity doesn't become dirty just by changing a mapped-by field (this was also true for reflection mode until build 2.2.6_03 and was changed in order to fix orphan removal). If Customer is not dirty - it doesn't cascade persisting of the referenced new Item instance.

ObjectDB Support
edit
delete
#5

I've added a line with em.contains check, so merge is called only on detached entities. If objectdb follows jpa, maybe we should ask jpa creators for the reason.

edit
delete
#6

This strange behavior is the result of two separate merge rules:

  • Merge of a managed entity object doesn't affect that entity object but is cascaded to referenced entity objects.
  • Merge of a non managed new entity object persists a new managed copy of the object (a clone).

Each rule is reasonable by its own, but the combination results in an automatic unexpected persistence operation.

Your solution seems to be the right thing to do.

ObjectDB Support
edit
delete

Reply

To post on this website please sign in.