EntityManager.merge()
kan nieuwe objecten invoegen en bestaande objecten bijwerken.
Waarom zou je persist()
willen gebruiken (die alleen nieuwe objecten kan maken)?
Beide manieren zullen een entiteit aan een PersistenceContext toevoegen, het verschil zit in wat je daarna met de entiteit doet.
Persist neemt een entiteitsinstantie, voegt die toe aan de context en maakt die instantie beheerd (d.w.z. toekomstige updates van de entiteit worden bijgehouden).
Merge maakt een nieuwe instantie van je entiteit, kopieert de toestand van de aangeleverde entiteit, en maakt de nieuwe kopie beheerd. De instantie die je doorgeeft wordt niet beheerd (wijzigingen die je aanbrengt worden geen onderdeel van de transactie - tenzij je merge opnieuw aanroept).
Misschien helpt een codevoorbeeld.
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 en 3 zijn ruwweg gelijkwaardig, maar er zijn enkele situaties waarin je'zou willen gebruiken Scenario 2.
Ik merkte dat wanneer ik em.merge
gebruikte, ik een SELECT
statement kreeg voor elke INSERT
, zelfs wanneer er geen veld was dat JPA voor mij genereerde-het primaire sleutelveld was een UUID dat ik zelf had ingesteld. Ik schakelde over naar em.persist(myEntityObject)
en kreeg toen alleen INSERT
statements.
Ik kreeg lazyLoading excepties op mijn entiteit omdat ik toegang probeerde te krijgen tot een lazy loaded collection die in session was.
Wat ik deed was in een apart verzoek de entiteit ophalen uit de sessie en dan proberen toegang te krijgen tot een collectie in mijn jsp pagina wat problematisch was.
Om dit te verhelpen heb ik dezelfde entiteit in mijn controller geupdate en doorgegeven aan mijn jsp, hoewel ik me voorstel dat als ik hem opnieuw in sessie opsla dat hij ook toegankelijk zal zijn via SessionScope
en geen LazyLoadingException
zal gooien, een modificatie van voorbeeld 2:
Het volgende heeft voor mij gewerkt:
// 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!!