Blog
JPA-Implementierungsmuster: Speichern von (abgetrennten) Entitäten

Wir haben unsere Suche nach JPA-Implementierungsmustern mit dem Data Access Object-Muster begonnen und mit der Diskussion über die Verwaltung bidirektionaler Assoziationen fortgesetzt. Diese Woche befassen wir uns mit einem Thema, das auf den ersten Blick trivial erscheinen mag: wie man eine Entität speichert.
Das Speichern einer Entität in JPA ist einfach, oder? Wir übergeben einfach das Objekt, das wir persistieren möchten, an
Was ist also die losgelöste Entität, von der in der Nachricht die Rede ist? Eine abgetrennte Entität (auch als abgetrenntes Objekt bezeichnet) ist ein Objekt, das dieselbe ID wie eine Entität im Persistenzspeicher hat, aber nicht mehr Teil eines Persistenzkontexts ist (der Bereich einer
- Der EntityManager, aus dem das Objekt abgerufen wurde, wurde geschlossen.
- Das Objekt wurde von außerhalb unserer Anwendung empfangen, z.B. als Teil einer Formularübermittlung, eines Remoting-Protokolls wie Hessian oder über einen BlazeDS AMF Channel von einem Flex-Client.
Der Vertrag für persist (siehe Abschnitt 3.2.1 der JPA 1.0-Spezifikation) besagt ausdrücklich, dass die persist-Methode eine EntityExistsException auslöst, wenn das übergebene Objekt eine abgetrennte Entität ist. Oder jede andere PersistenceException ausgelöst wird, wenn der Persistenzkontext geleert oder die Transaktion übertragen wird. Beachten Sie, dass es kein Problem ist, dasselbe Objekt zweimal innerhalb einer Transaktion zu persistieren. Der zweite Aufruf wird einfach ignoriert, obwohl die Persist-Operation möglicherweise auf alle Assoziationen der Entität kaskadiert wird, die seit dem ersten Aufruf hinzugefügt wurden. Abgesehen von der letztgenannten Überlegung besteht keine Notwendigkeit, EntityManager.persist für eine bereits persistierte Entität aufzurufen, da alle Änderungen beim Flush oder Commit automatisch gespeichert werden.
saveOrUpdate vs. Zusammenführen
Diejenigen unter Ihnen, die mit einfachem Hibernate gearbeitet haben, werden sich wahrscheinlich schon an die Verwendung der Session.saveOrUpdate Methode zu verwenden, um Entitäten zu speichern. Die
Alles zusammenfügen
Lassen Sie uns also die drei möglichen Fälle untersuchen und was die verschiedenen Methoden bewirken:
| Szenario | EntityManager.persist | EntityManager.merge | SessionManager.saveOrUpdate |
|---|---|---|---|
| Übergebenes Objekt wurde nie persistiert | 1. Objekt wurde dem Persistenzkontext als neue Entität hinzugefügt 2. Neue Entität wird beim Flush/Commit in die Datenbank eingefügt | 1. Zustand wird in die neue Entität kopiert. 2. Neue Entität wird zum Persistenzkontext hinzugefügt 3. Neue Entität beim Flush/Commit in die Datenbank eingefügt 4. Neue Entität zurückgegeben | 1. Objekt wird dem Persistenzkontext als neue Entität hinzugefügt 2. Neue Entität bei Flush/Commit in die Datenbank eingefügt |
| Objekt wurde zuvor persistiert, aber nicht in diesen Persistenzkontext geladen | 1. EntityExistsException ausgelöst (oder eine PersistenceException beim Flush/Commit) | 2. Vorhandene Entität geladen. 2. Status von Objekt zu geladener Entität kopiert 3. Geladene Entität wird beim Flush/Commit in der Datenbank aktualisiert 4. Geladene Entität zurückgegeben | 1. Objekt zum Persistenzkontext hinzugefügt 2. Geladene Entität wird beim Flush/Commit in der Datenbank aktualisiert |
| Objekt wurde zuvor persistiert und bereits in diesen Persistenzkontext geladen | 1. EntityExistsException ausgelöst (oder eine PersistenceException zum Zeitpunkt des Flush oder Commit) | 1. Zustand des Objekts wird in die geladene Entität kopiert 2. Geladene Entität wird beim Flush/Commit in der Datenbank aktualisiert 3. Geladene Entität zurückgegeben | 1. NonUniqueObjectException ausgelöst |
Wenn man sich diese Tabelle ansieht, versteht man vielleicht, warum die saveOrUpdate-Methode nie Teil der JPA-Spezifikation wurde und warum sich die JSR-Mitglieder stattdessen für die Merge-Methode entschieden haben. Übrigens finden Sie im Blog von Stevi Deter einen anderen Blickwinkel auf das saveOrUpdate vs. merge Problem.
Das Problem mit der Zusammenführung
Bevor wir fortfahren, müssen wir einen Nachteil der Funktionsweise von EntityManager.merge erörtern: Bidirektionale Verknüpfungen können leicht unterbrochen werden. Betrachten Sie das Beispiel mit den Klassen
Order existingOrder = dao.findById(receivedOrder.getId());
if(existingOrder == null) {
dao.persist(receivedOrder);
} sonst {
existingOrder.setCustomerName(receivedOrder.getCustomerName());
existingOrder.setDate(receivedOrder.getDate());
}
Das Muster
Was bedeutet das alles für uns? Die Faustregel, an die ich mich halte, lautet wie folgt:
- Wenn und nur wenn (und vorzugsweise wo) wir eine neue Entität erstellen, rufen Sie EntityManager.persist auf, um sie zu speichern. Das macht durchaus Sinn, wenn wir unsere
Domänenzugriffsobjekte als Sammlungen betrachten. Ich nenne dies das persist-on-new Muster. - Wenn wir eine bestehende Entität aktualisieren, rufen wir keine EntityManager-Methode auf. Der JPA-Anbieter aktualisiert die Datenbank automatisch zum Zeitpunkt des Flush oder Commit.
- Wenn wir eine aktualisierte Version einer bestehenden einfachen Entität (eine Entität ohne Verweise auf andere Entitäten) von außerhalb unserer Anwendung erhalten und den neuen Zustand speichern möchten, rufen wir EntityManager.merge auf, um diesen Zustand in den Persistenzkontext zu kopieren. Aufgrund der Art und Weise, wie das Zusammenführen funktioniert, können wir dies auch tun, wenn wir uns nicht sicher sind, ob das Objekt bereits persistiert wurde.
- Wenn wir mehr Kontrolle über den Zusammenführungsprozess benötigen, verwenden wir das DIY-Zusammenführungsmuster.
Ich hoffe, dieser Blog gibt Ihnen einige Hinweise darauf, wie Sie Entitäten speichern und wie Sie mit abgetrennten Entitäten arbeiten können. Wir werden auf abgetrennte Entitäten zurückkommen, wenn wir in einem späteren Blog über Data Transfer Objects sprechen. In der nächsten Woche werden wir uns jedoch zunächst mit einer Reihe gängiger Abfragemuster für Entitäten befassen. In der Zwischenzeit freuen wir uns über Ihr Feedback. Was sind Ihre JPA-Muster? Eine Liste aller Blogs zu JPA-Implementierungsmustern finden Sie in der Zusammenfassung der JPA-Implementierungsmuster.
Verfasst von
Vincent Partington
Unsere Ideen
Weitere Blogs
Contact



