This blog article is part of a “series of blog articles” about common pitfalls using JPA and ways to avoid them. In this article, we describe a common error when using EntityManager.merge.
The EnityManager interface provides a method merge
to merge the state of a detached entity into the current persistence context.
The following lines of code show an error prone usage pattern of the merge
method:
Department dept = ... // detached Department instance
em.merge(dept);
dept.setFirstname("New name");
Please note, the code ignores the instance being returned by the merge
method. It returns the managed instance the state was merged to. There are two cases:
- The current persistence context does not include an entity with the id of the instance passed to the
merge
call. Then the instance is stored into the persistence context and returned by themerge
method. - The current persistence context already has an entity with the id of the instance passed to the
merge
call. The state of the passed instance is merged into the existing entity. The methodmerge
returns the existing entity. That means the instance passed as an argument is still in the detached state.
The correct code used the return instance for any other changes:
Department dept = ... // detached Department instance
dept = em.merge(dept);
dept.setFirstname("New name");
The above error is very tricky, because it depends on the state of the current persistence context. Furthermore, it does not throw an exception in the error case, instead the update statement changes the detached instance, so nothing get store in the database.
Recommendation: Always use the return value of EnityManager.merge
.
You can find an example of this pitfall and its solution in the class DuplicatesInQueryResultExperiment in this project: https://github.com/akquinet/jpapitfalls.git.