JPA EntityManager: Perché usare persist() invece di merge()?

L'EntityManager.merge()`può inserire nuovi oggetti e aggiornare quelli esistenti.

Perché si dovrebbe voler usare persist() (che può solo creare nuovi oggetti)?

Soluzione

Entrambi i modi aggiungeranno un'entità a un PersistenceContext, la differenza è in ciò che si fa con l'entità dopo.

Persist prende un'istanza di entità, la aggiunge al contesto e rende quell'istanza gestita (cioè i futuri aggiornamenti dell'entità saranno tracciati).

Merge crea una nuova istanza della vostra entità, copia lo stato dall'entità fornita e rende la nuova copia gestita. L'istanza che passate non sarà gestita (qualsiasi modifica apportata non sarà parte della transazione - a meno che non chiamiate nuovamente merge).

Forse un esempio di codice aiuterà.

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)

Lo scenario 1 e 3 sono approssimativamente equivalenti, ma ci sono alcune situazioni in cui si vorrebbe usare lo scenario 2.

Commentari (12)

Ho notato che quando ho usato em.merge, ho ottenuto una dichiarazione SELECT per ogni INSERT, anche quando non c'era nessun campo che JPA stava generando per me - il campo chiave primaria era un UUID che ho impostato io stesso. Sono passato a em.persist(myEntityObject) e ho ottenuto solo dichiarazioni INSERT.

Commentari (2)

Stavo ottenendo eccezioni lazyLoading sulla mia entità perché stavo cercando di accedere a una collezione caricata pigramente che era in sessione.

Quello che avrei fatto era in una richiesta separata, recuperare l'entità dalla sessione e poi provare ad accedere a una collezione nella mia pagina jsp che era problematica.

Per alleviare questo, ho aggiornato la stessa entità nel mio controller e l'ho passata alla mia jsp, anche se immagino che quando ho salvato di nuovo in sessione sarà accessibile anche se SessionScope e non lancerà una LazyLoadingException, una modifica dell'esempio 2:

Il seguente ha funzionato per 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!!
Commentari (0)