views:

16878

answers:

4

EntityManager.merge() can insert new objects and update existing ones.

Why would one want to use persist() (which can only create new objects)?

+9  A: 

a worthy discussion about merge vs persist

dfa
+45  A: 

Either way will add an entity to a PersistenceContext, the difference is in what you do with the entity afterwards.

Persist takes an entity instance, adds it to the context and makes that instance managed (ie future updates to the entity will be tracked)

Merge creates a new instance of your entity, copies the state from the supplied entity, and makes the new copy managed. The instance you pass in will not be managed (any changes you make will not be part of the transaction - unless you call merge again).

Maybe a code example will help.

MyEntity e = new MyEntity();

// scenario 1
// tran starts
em.persist(e); 
e.setSomeField(someValue); 
// tran ends, and the row for someField is updated in the database

// scenario 2
// tran starts
e = new MyEntity();
em.merge(e);
e.setSomeField(anotherValue); 
// tran ends but the row for someField is not updated in the database (you made the changes *after* merging

// scenario 3
// tran starts
e = new MyEntity();
MyEntity e2 = em.merge(e);
e2.setSomeField(anotherValue); 
// tran ends and the row for someField is updated (the changes were made to e2, not e)

Scenario 1 and 3 are roughly equivalent, but there are some situations where you'd want to use Scenario 2.

Mike
Upvoted. Straight to point and good reference material.
James P.
@Mike: I would like to use `Session.persist()` for detached entity, but first I need to re-associate it with session. Unfortunately, `Session.lock(entity, LockMode.NONE)` fails with exception saying that lazy collections are not initialized. Am I doing something wrong?
dma_k
@dma_k: Looks like you're using Hibernate. I'm less familiar with Hibernate than JPA - but in JPA if you call EntityManager.persist() and pass in a detached entity you will: a) get an EntityExistsException immediatelyorb) get another PersistenceException at flush / commit time. Maybe I've misunderstood the question here?
Mike
A: 

Thank you for the very informative answer. "but there are some situations where you'd want to use Scenario 2" Any examples of such situations? The only case I ca think of is when we need to create multiple, identical entities. Thanks!

Basel
Either post this as a comment to the answer or create a new question, please.
Aaron Digulla
A: 

I was getting lazyLoading exceptions on my entity because I was trying to access a lazy loaded collection that was in session.
What I would do was in a separate request, retrieve the entity from session and then try to access a collection in my jsp page which was problematic.
To alleviate this, I updated the same entity in my controller and passed it to my jsp, although I imagine when I re-saved in session that it will also be accessible though $SessionScope and not throw a lazyLoadingException, a modification of example 2:
The following has worked for me:
// scenario 2 MY WAY
// tran starts
e = new MyEntity();
e = em.merge(e); // re-assign to the same entity "e"

//access e from jsp and it will work dandy!!

logixplayer