JPA EntityManager: Hvorfor bruke persist() fremfor merge()?

EntityManager.merge() kan sette inn nye objekter og oppdatere eksisterende.

Hvorfor skulle man ønske å bruke persist() (som bare kan opprette nye objekter)?

Løsning

Begge måtene legger til en entitet i en PersistenceContext, forskjellen ligger i hva du gjør med entiteten etterpå.

Persist tar en entitetsforekomst, legger den til konteksten og gjør forekomsten administrert (dvs. at fremtidige oppdateringer av entiteten spores).

Merge oppretter en ny forekomst av entiteten, kopierer tilstanden fra den leverte entiteten og gjør den nye kopien administrert. Instansen du sender inn, blir ikke administrert (eventuelle endringer du gjør, blir ikke en del av transaksjonen - med mindre du kaller merge igjen).

Kanskje et kodeeksempel kan være til hjelp.

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 og 3 er noenlunde likeverdige, men det finnes noen situasjoner der det kan være lurt å bruke scenario 2.

Kommentarer (12)

Jeg la merke til at når jeg brukte em.merge, fikk jeg en SELECT-setning for hver INSERT, selv når det ikke var noe felt som JPA genererte for meg - primærnøkkelfeltet var en UUID som jeg satte selv. Jeg byttet til em.persist(myEntityObject) og fikk bare INSERT-setninger da.

Kommentarer (2)

Jeg fikk lazyLoading-unntak på enheten min fordi jeg prøvde å få tilgang til en lazy loaded samling som var i session.

Det jeg gjorde, var å hente entiteten fra økten i en separat forespørsel og deretter prøve å få tilgang til en samling på jsp-siden, noe som var problematisk.

For å avhjelpe dette oppdaterte jeg den samme entiteten i kontrolleren min og sendte den til jsp-siden min, selv om jeg forestiller meg at når jeg lagrer på nytt i sesjonen, vil den også være tilgjengelig via SessionScope og ikke kaste en LazyLoadingException, en modifikasjon av eksempel 2:

Følgende har fungert for meg:

// 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!!
Kommentarer (0)