Here is an OpenJPA 1.2.1 example that demonstrates the "OpenJPA replaces a collection field" problem. This may not be technically a bug but it can be a problem for the unaware user.

This happens with a new persisted object with a collection field that is initially null. If the null collection is initialized to an empty collection it will correctly register additions until it is flushed. Then the collection field is replaced and the old collection is stale.

In this example the flush is an explicit call. But the same problem happens when the object is implicitly flushed to get the generated identity for a foreign key.

In the main program the behavior changes when "em.flush()" is commented out.

================= LazyLoadTest.java ==============
package com.jpatest;

import javax.persistence.*;
import java.util.*;

import com.jpatest.persistence.*;

public class LazyLoadTest
{
   public static void main(String args[])
       throws Throwable
   {
EntityManagerFactory emf = Persistence.createEntityManagerFactory("jpatest");
       EntityManager em = emf.createEntityManager();
       em.getTransaction().begin();
       ListHolder holder = new ListHolder();
       em.persist(holder);
       List<ListMember> listReference = holder.getMembers();
       em.persist(new ListMember(holder));
System.err.println("id="+holder.id+" size[expect=1]="+listReference.size());

       em.persist(new ListMember(holder));
System.err.println("id="+holder.id+" size[expect=2]="+listReference.size());

       em.flush(); // **** this causes problem when uncommented
       em.persist(new ListMember(holder));
System.err.println("id="+holder.id+" size[expect=3]="+listReference.size());

       em.getTransaction().commit();
       em.close();
   }
}


================= ListHolder.java ==============
package com.jpatest.persistence;

import java.util.*;
import javax.persistence.*;

@Entity
@Table (name="list_holder")
public class ListHolder
   implements java.io.Serializable
{
   @GeneratedValue(strategy=GenerationType.IDENTITY)
   @Id public long id;
   @Version private long version;

   @OneToMany(mappedBy="holder", fetch=FetchType.LAZY,
              cascade={CascadeType.PERSIST,CascadeType.REMOVE})
   private List<ListMember> members;

   public ListHolder() {}

   public List<ListMember> getMembers()
   {
       if (members == null) {
           System.err.println("---- ListHolder members == null");
           members = new ArrayList<ListMember>();
       }
       return members;
   }
}

================= ListMember.java ==============
package com.jpatest.persistence;

import javax.persistence.*;

@Entity
@Table (name="list_member")
public class ListMember
   implements java.io.Serializable
{
   @GeneratedValue(strategy=GenerationType.IDENTITY)
   @Id private long id;
   @Version private long version;

   @ManyToOne (optional=false,fetch=FetchType.LAZY,cascade=CascadeType.ALL)
   private ListHolder holder;

   protected ListMember() {}
   public ListMember(ListHolder holder)
   {
       this.holder = holder;
       holder.getMembers().add(this);
   }
}


Reply via email to