Search code examples
eclipselinkjava-ee-7jpa-2.1glassfish-4.1

Entity data reset when a lazy LOB is changed


I'm working on a big project using Glassfish 4 (JavaEE7) and EclipseLink (JPA2.1). When I modify the value of a LOB field, this resets all the previous value of then entity.

For instance, I have the following entity:

@Entity
@Table(name="person")
public class Person implements Serializable {
    @Id
    @Column(name = "ID")
    private Integer id;
    @Column(name = "LASTNAME")
    private String lastname;
    @Column(name = "FIRSTNAME")
    private String firstname;
    @Column(name = "VERSION")
    private Integer version;
    @Lob
    @Basic(fetch = FetchType.LAZY)
    @Column(name = "REMARKS")
    private String remarks;

    /* getter & setters */
}

I use the following code to update my entity:

@Singleton
@TransactionManagement(TransactionManagementType.BEAN)
@Startup
public class ModifierBean implements ModifierBeanLocal {

    @Resource
    private UserTransaction userTransaction;

    @PersistenceContext
    private EntityManager entityManager;

    @Override
    public String modify(Integer id, String lastname, String firstname, String remarks) {
        try {
            StringBuilder result = new StringBuilder(256);

            userTransaction.begin();
            Query query = entityManager.createQuery("SELECT p FROM Person p WHERE p.id = ?1");
            query.setParameter(1, id);

            Person p = (Person)query.getSingleResult();
            result.append("State 0: lastname=").append(p.getLastname()).append(", firstname=").append(p.getFirstname()).append(", version=").append(p.getVersion()).append("<br />");

            p.setFirstname(firstname);
            p.setLastname(lastname);
            p.setVersion(p.getVersion()+1);
            result.append("State 1: lastname=").append(p.getLastname()).append(", firstname=").append(p.getFirstname()).append(", version=").append(p.getVersion()).append("<br />");

            p.setRemarks(remarks); //  <= reset the other fields
            result.append("State 2: lastname=").append(p.getLastname()).append(", firstname=").append(p.getFirstname()).append(", version=").append(p.getVersion()).append("<br />");

            userTransaction.commit();
            return result.toString();
        } catch(Exception e) {
            //...
        }
    }
}

When I'm running the following code, here is the output I get from the Bean:

State 0: lastname=Smith, firstname=John, version=0
State 1: lastname=John2, firstname=Smith2, version=1
State 2: lastname=Smith, firstname=John, version=0

As one can see, the values of then entity are reset when LOB is loaded, which is very annoying for my purpose. There are some tricks to prevent that to happen, for instance I tested the following options:

  • call entityManager.flush() just before the modification of the LOB field
  • call p.getRemarks() juste before doing the first modifications

I also noticed that if the LOB field is not changed, then the values are correctly committed. I know that a LAZY value is loaded on demand but I do not understand why it resets all the other values.

Is this a bug or a standard behaviour ? Is there any way to make it work as expected (no reset of value) ?


Solution

  • I just found out that this exact bug has been open in EclipseLink (already present since v2.1.3): https://bugs.eclipse.org/bugs/show_bug.cgi?id=371743