JPA mit JTA: Persist entity-und merge-Kaskaden-Kind-Entitäten
Habe ich eine bidirektionale eins-zu-viele-Beziehung mit den folgenden Entitäten:
0 oder 1 client <-> 0 oder mehr Bestellungen von Produkten
Beim speichern des client-Entität, möchte ich das Produkt, um Entitäten beibehalten werden, auch (als deren Fremdschlüssel auf die "Eltern" - client können aktualisiert worden sein).
Natürlich alle erforderlichen CASCADE-Optionen auf der client-Seite. Aber es funktioniert nicht, wenn eine neu erstellte client persistiert wird zum ersten mal während der Referenzierung eines bereits bestehenden Produktes, um wie in diesem Szenario:
- Produkt bestellen '1' erzeugt und persistiert. Funktioniert einwandfrei.
- client '2' angelegt und ein Produkt, um '1' ist Hinzugefügt, um seine Produkt-Aufträge-Liste. Dann ist es permanent. Funktioniert nicht.
Ich habe versucht, mehrere apporaches, aber keiner von Ihnen zeigte das erwartete Ergebnis. Sehen die Ergebnisse unter. Ich Lesen Sie alle Fragen hier, aber Sie wollten mir nicht helfen. Ich benutze EclipseLink 2.3.0, reines JPA 2.0 Annotations, und JTA-transaction-Typ, die auf einem Apache Derby (JavaDB) in-memory DB auf GlassFish 3.1.2. Entität Beziehungen verwaltet werden, die von einer JSF-GUI. Objekt-Ebene-relationship-management-funktioniert (abgesehen von persistierenden), getestet habe ich es mit JUnit-tests.
Ansatz 1) "Standard" (basiert auf NetBeans-Klassen-templates)
Client:
@Entity
public class Client implements Serializable, ParentEntity {
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
@OneToMany(mappedBy = "client", cascade={CascadeType.PERSIST, CascadeType.MERGE, CascadeType.REFRESH},
fetch= FetchType.LAZY)
private List<ProductOrder> orders = new ArrayList<>();
//other fields, getters and setters
}
ProductOrder:
@Entity
public class ProductOrder implements Serializable, ChildEntity {
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
@ManyToOne //owning side
private Client client;
//other fields, getters and setters
}
Generische Persistenz Fassade:
//Called when pressing "save" on the "create new..." JSF page
public void create(T entity) {
getEntityManager().persist(entity);
}
//Called when pressing "save" on the "edit..." JSF page
public void edit(T entity) {
getEntityManager().merge(entity);
}
Ergebnis:
create() wirft diese Ausnahme sofort:
Achtung: Eine Ausnahme ist aufgetreten, während eine Anrufung auf EJB
ClientFacade Methode public void
javaee6test.Bohnen.AbstractFacade.erstellen(java.lang.Objekt)
javax.ejb.EJBException: Transaktion abgebrochen ...Verursacht durch:
javax.die Transaktion.RollbackException: Transaktion gekennzeichnet sind, für die das rollback.
...Verursacht durch: Exception [EclipseLink-4002] (Eclipse Persistence
Dienstleistungen - 2.3.0.v20110604-r9504):
org.eclipse.die Persistenz.Ausnahmen.DatabaseException Internal
Ausnahme: java.sql.SQLIntegrityConstraintViolationException:
Anweisung wurde abgebrochen, weil es würde verursacht haben einen doppelten Schlüssel
Wert in einer unique-oder primary key-Einschränkung oder einen eindeutigen index identifiziert
durch 'SQL120513133540930' definiert 'PRODUCTORDER'. Error Code: -1
Aufruf: INSERT INTO PRODUCTORDER (ID, CLIENT_ID) VALUES (?, ?) binden =>
[2 Parameter gebunden] Query:
InsertObjectQuery(javaee6test.Modell.ProductOrder[ id=1 ]) ...Verursacht durch:
java.sql.SQLIntegrityConstraintViolationException: Die Aussage war
abgebrochen, weil es würde verursacht haben einen doppelten Schlüsselwert in einer einzigartigen
oder primary key-Einschränkung oder einen eindeutigen index gekennzeichnet durch
'SQL120513133540930' definiert 'PRO-DUCTORDER'. ...Verursacht durch:
org.apache.derby.client.bin.SqlException: Die Anweisung wurde abgebrochen
werden-die es verursachen würde verursacht haben einen doppelten Schlüssel, Wert in einer unique-oder
primary key-Einschränkung oder einen eindeutigen index gekennzeichnet durch
'SQL120513133540930' definiert 'PRODUCTOR-DER'.
Ich verstehe nicht diese Ausnahme. Bearbeiten() funktioniert Prima. ABER ich möchte hinzufügen, Produkt-Aufträge zu einem Kunden in seine Erstellung Zeit, so ist dies unzureichend.
Ansatz 2) merge() nur
Änderungen Generische Persistenz Fassade:
//Called when pressing "save" on the "create new..." JSF page
public void create(T entity) {
getEntityManager().merge(entity);
}
//Called when pressing "save" on the "edit..." JSF page
public void edit(T entity) {
getEntityManager().merge(entity);
}
Ergebnis:
Create(), die EclipseLink-Logging-Ausgabe, sagt:
Fein: INSERT INTO KUNDEN (ID, NAME, ADDRESS_ID) VALUES (?, ?, ?)
binden => [3 Parameter gebunden]
aber KEIN "UPDATE" auf der Produkt-Tabelle. So, die Beziehung ist nicht etabliert. Wieder "Bearbeiten" (), auf der anderen Seite, funktioniert gut.
Apporach 3) Id GenerationType.IDENTITÄT auf beiden entity-Typen
Änderungen an client-und Produkt bestellen, Klasse:
...
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
...
Ergebnis:
Create(), die EclipseLink-Logging-Ausgabe, sagt:
Fein: INSERT INTO KUNDEN (NAME, ADDRESS_ID) VALUES (?, ?) binden => [2
Parameter gebunden]Fein: Werte IDENTITY_VAL_LOCAL()
Fein: INSERT INTO
PRODUCTORDER ("ORDERDATE", CLIENT_ID) VALUES (?, ?) binden => [2
Parameter gebunden]Fein: Werte IDENTITY_VAL_LOCAL()
also statt estabilshing eine Beziehung zu dem Produkt Hinzugefügt, um die client-Liste, ein neues Produkt, um entity wird erstellt und persistiert (!) und eine Beziehung zu dieser Entität ist estabilshed. Hier gilt das gleiche, Bearbeiten() funktioniert Prima.
Apporach 4) Ansatz (2) und (3) kombiniert
Ergebnis: die Gleichen wie im Ansatz (2).
Meine Frage ist: gibt es eine Möglichkeit zu erkennen, das oben beschriebene Szenario? Wie kann es werden erreicht? Ich möchte bleiben mit JPA (kein vendor-spezifische Lösung).
InformationsquelleAutor der Frage SputNick | 2012-06-14
Du musst angemeldet sein, um einen Kommentar abzugeben.
Hi ich hatte das gleiche problem heute, Frage ich, um die openJPA-mailing-Liste mit dieser E-Mail:
Hallo. Ich habe ein problem mit insert-und Update-Referenz in der gleichen Person.
Ich versuche ein neues Objekt eingefügt (Prüfung), die einen Verweis auf ein anderes Objekt (Person) und gleichzeitig möchte ich ein Attribut aktualisieren (Geburtsdatum) des Person-Objekts. Das update nie passiert, obwohl ich CascadeType für ALLE. Der einzige Weg, den dies funktioniert, ist dabei eine anhalten und nach, dass ein merge-Vorgang. Ist das normal? Muss ich etwas ändern??
Ich nicht wie die Idee von einem "manuellen update" mit merge in das Objekt Person, denn ich weiß nicht, wie viele Objekte (child-Objekt der Prüfung) der Benutzer aktualisieren möchten.
Personen:
Tun, ich habe die Verwendung der MERGE-Methode für jedes Kind-Objekt?
Und die Antwort war diese:
Wie es aussieht, dein problem ist, dass die Prüfung ist neu, noch die Person ist
der bestehende und der bestehende Einheit wird ignoriert, wenn die Kaskadierung bestehen
Betrieb. Ich glaube, dass diese wie erwartet funktioniert.
So lange, wie Sie Ihre Beziehungen festgelegt sind, CascadeType.ALLE konnten Sie immer
ändern Sie Ihre em.bestehen(Prüfung); em.merge(Prüfung);. Das würde aufpassen
das verharren der neuen Prüfung, und es würden auch die Kaskade der merge-Aufruf der
person.
Dank,
Rick
Ich hoffe das kann dir helfen.
InformationsquelleAutor der Antwort maxtorzito
@SputNick ,ich löste es, indem Sie die unten beschriebenen Schritte.Ich werde verwenden Sie Ihre code-snippet zu zeigen, was ich habe,
Haben Sie Client-entity -@OneToMany und ProductOrder entity -@ManyToOne .Ich werde
für die Persistenz, wie es mir die Flexibilität zu speichern wie auch zu aktualisieren.
Erstellen Client und entsprechenden Produkt-Bestellungen verwenden
//Set productOrder für die client -
client.setOrders(order);
//Beachten Sie, dass diese erwartet eine Liste übergeben werden//client für die productOrder
Beachten Sie, dass beide Wege werden in der Lage sein zu aktualisieren, sowohl entity-Tabellen mit Ihren änderungen.
Obwohl spät,hoffe, es hilft jemand
InformationsquelleAutor der Antwort Fredrick Aponyo
Verwendung von @Joincolumn-annotation in Ihrem ProductOrder Entität, sehen Sie bitte unten.
InformationsquelleAutor der Antwort Sai Ye Yan Naing Aye
Sicherzustellen, dass Sie sind, indem beide Seiten der Beziehung, Sie können nicht einfach hinzufügen, um den client, Sie müssen auch die AUFTRAGGEBER der Bestellung. Auch Sie brauchen, um mischen der beiden Objekte, die Sie geändert haben. Wenn Sie nur Zusammenführen der Kunde, dann, um den client nicht zusammengeführt werden (obwohl Ihr die Kaskade, die Sie verursachen es, die zusammengeführt werden).
anhalten funktioniert nicht, da bestehen erfordert, dass das Objekt beibehalten wird richtig sein für die Persistenz-Kontext, also nicht auf freistehende Objekte, mit Bezug auf verwaltete Objekte.
Dein Problem kommt von Ihnen trennen der Objekte. Wenn Sie nicht trennen Sie die Objekte, die Sie würde nicht die gleichen Probleme haben. Normalerweise wird in JPA erstellen Sie einen EntityManager, finden/query-Objekte, Bearbeiten/bestehen, so rufen Sie Begehen. Keine Zusammenlegung erforderlich ist.
InformationsquelleAutor der Antwort James