Merge the object, change its identifier, merge again, call "mapped to the primary key column in the database. Update failed"

I have a JPA program where EclipseLink is a containment provider. When I merge a user object, change its identifier and try to merge the same user instance again, an error occurs. I am rewriting my code to illustrate my problem in the easiest way.

User user = userManager.find(1); userManager.merge(user); System.out.println("User is managed? "+userManager.contains(user); user.setId(2); userManager.merge(user); 

The above code is not in the context of a transaction. userManager is a non-bean session with EntityManager entered. When executed, the console prints:

 User is managed? false Exception [EclipseLink-7251] (Eclipse Persistence Services - 2.1.3.v20110304-r9073): org.eclipse.persistence.exceptions.ValidationException Exception Description: The attribute [id] of class [demo.model.User] is mapped to a primary key column in the database. Updates are not allowed. 

An exception occurs in the second call to merge ().

If I create a new user, sets his identifier and combines it, it works:

 User user = userManager.find(1); userManager.merge(user); System.out.println("User is managed? "+userManager.contains(user); User newUser = new User(); newUser.setId(2); userManager.merge(newUser); 

So what is the difference between the first scenario and the second? According to the JPA specification, as long as the object is in a detached state, the merge must be successful, right? (Assuming an object with ID = 2 exists)

Why does the EclipseLink provider seem concerned about the fact that the user object was merged before?

Update: this seems to be an EclipseLink error. I replaced the persistence provider from EclipseLink to Hibernate:

I am changing

 <provider>org.eclipse.persistence.jpa.PersistenceProvider</provider> 

to

 <provider>org.hibernate.ejb.HibernatePersistence</provider> 

No error has been selected.

+7
source share
4 answers

This seems to be an EclipseLink bug. I changed the continuity provider from EclipseLink to Hibernate:

from

 <provider>org.eclipse.persistence.jpa.PersistenceProvider</provider> 

to

 <provider>org.hibernate.ejb.HibernatePersistence</provider> 

Error was not sent.

EclipseLink version is 2.3.2. (which comes with the latest Glassfish 3.1.2 application server).

The hibernate version is currently the latest, 4.1.7.

+2
source

The reason is that Id can be inserted / defined - as in the second example, but not changed / updated as you try in the first example. The JPA provider is trying to reflect changes in the database and is not working.

JPA 2 spec ยง2.4 says

An application should not change the value of a primary key. undefined behavior if this occurs.

+3
source

Try <property name="eclipselink.weaving.internal" value="false"/> in the persistence.xml file according to http://blogs.nologin.es/rickyepoderi/index.php?/archives/95-Weaving- Problem-in-EclipseLink.html

+1
source

This answer has been completed for 4 years, but in any case.

You can update it by running regular update requests using SQL or JPQL or API criteria . I believe the latter is the best.

Here is an example of code that can do the trick. I tried it in a similar situation and it works great with EclipseLink.

 CriteriaBuilder cb = em.getCriteriaBuilder(); CriteriaUpdate<User> cu = cb.createCriteriaUpdate(User.class); Root<User> c = cu.from(User.class); cu.set(User_.id, newId).where( cb.equal(c.get(User_.id), oldId) ); em.createQuery(cu).executeUpdate(); 

Instead of User_.id, you can pass the field name as a string, for example. "Identifier".

Another example is http://www.thoughts-on-java.org/criteria-updatedelete-easy-way-to/

0
source

All Articles