views:

391

answers:

2

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()?

+1  A: 

Use update() if you are sure that the session does not contain an already persistent instance with the same identifier and merge() if you want to merge your modifications at any time without consideration of the state of the session. In other words update() is usually the first method you would call in a fresh session ensuring that reattachment of your detached instances is the first operation that is executed.

Mark R
+5  A: 

Hi,

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 can think him or her 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

  • Add a version (@Version) column. 0 or NULL version indicates that an instance is new and has to be inserted, not updated
  • Use a Hibernate interceptor
  • If you are sure you want to update instead of inserting, you can use the following approach

...

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. Maybe you want to see this Best way to update some fields of a detached object on Hibernate ? question

regards,

Arthur Ronald F D Garcia