I'm having problems with a NonUniqueObjectException
thrown by Hibernate.
Reading the docs, and this blog post, I replaced the call from update()
to merge()
, and it solved the problem.
I believe I understand the reason for the exception, and why changing the method fixed the problem, in terms of disconnected objects and session boundaries.
My question is : given that merge()
will always resolve to the session object, or retrieve it if it doesn't exist, is calling merge() generally a safer alternative than update()
?
What is the downside of using merge()
over update()
?
Hibernate handles persisting any changes to objects in the session when the session is flushed. update can fail if an instance of the object is already in the session. Merge should be used in that case. It merges the changes of the detached object with an object in the session, if it exists.
Persist should be called only on new entities, while merge is meant to reattach detached entities. If you're using the assigned generator, using merge instead of persist can cause a redundant SQL statement.
Hibernate merge can be used to update existing values, however this method create a copy from the passed entity object and return it. The returned object is part of persistent context and tracked for any changes, passed object is not tracked. This is the major difference with merge() from all other methods.
Merge returns the managed instance that the state was merged with. It does return something that exists in PersistenceContext or creates a new instance of your entity. In any case, it will copy the state from the supplied entity, and return a managed copy.
Is calling merge() generally a safer alternative than update() ?
As a way to avoid NonUniqueObjectException, yes. I think it explains why JPA does not allow an update method.
What is the downside of using merge() over update() ?
An unadvised user may think he or she has a fresh managed entity. Something like
// myEntity (passed as parameter does not become managed) // Only the one returned by the merge operation is a managed entity session.merge(myEntity); // "newValue" is not commited because myEntity is not managed myEntity.setMyProperty("newValue");
And if your persistence context does not contain your entity, maybe you do not want select-before-updating default behavior. But it can be avoided
...
public void updateMyEntity(MyEntity updateableMyEntity); // load does not hit the database MyEntity myEntity = (MyEntity) session.load(MyEntity.class, updateableMyEntity.getId()); BeanUtils.copyProperties(myEntity, updateableMyEntity); }
This way you can update your entity without merge or update method. See this question for more information: Best way to update some fields of a detached object on Hibernate ?
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With