Transient Entity im Ruhezustand verwenden, um ein vorhandenes persistentes Objekt zu aktualisieren / zusammenzuführen

8

Ich habe es mit einem ziemlich komplexen Objektgraphen in meiner Datenbank zu tun. Ich benutze XStream, um diesen Objektgraphen zu serialisieren und zu deserialisieren, was gut funktioniert. Wenn ich ein Objektdiagramm eines Objekts importiere, das in der Datenbank existiert, ist es anfänglich vorübergehend, da es keine IDs gibt und Hibernate nichts davon weiß. Ich habe dann eine Geschäftslogik, die IDs auf Teile meines Objektgraphen setzt, indem ich herausfinde, welche Objekte in dem neu vorübergehenden importierten Objekt existierenden persistenten Objekten zugeordnet werden. Ich verwende dann Hibernate's merge () und saveOrUpdate ().

Irgendein Pseudocode, um dir eine bessere Vorstellung davon zu geben, was ich mache:

%Vor%

Jetzt funktioniert das nicht, da ich Fehler wie:

erhalte %Vor%

und es scheint, als wäre die Hibernate Merge nicht dazu gedacht, transiente Objekte mit dauerhaften zu verknüpfen.

Gibt es eine Möglichkeit, das zu erreichen, was ich tun will, ohne das persistente Objekt in Sitzung zu bekommen und dieses zu modifizieren, statt das vorübergehende zu modifizieren und zu versuchen, das existierende persistente zu überschreiben?

    
eipark 15.03.2013, 14:54
quelle

2 Antworten

8
  

Es scheint, als wäre die Hibernate Merge nicht dazu gedacht, Transienten zu assoziieren   Objekte für persistente

Zusammenführen ist JPA-Standard - führt "neue & amp; abgelöste Entitätsinstanzen" zu "(im Persistenzkontext) verwaltete Entitätsinstanzen" zusammen. Kaskade über FK-Beziehungen, die mit Cascade.MERGE oder Cascade.ALL gekennzeichnet sind.

Aus einer Perspektive JPA - nein, die Zusammenführung war nicht dazu gedacht, Ihre streamed transienten Objekte in Xstream mit persistent zu verknüpfen. JPA beabsichtigt, dass Merge mit dem normalen JPA-Lebenszyklus arbeitet - neue Objekte erstellen, persistent machen, erhalten / finden, trennen, modifizieren (einschließlich Hinzufügen neuer Objekte), zusammenführen, optional modifizieren und dann persistieren / speichern . Dies ist bewusstes Design, so dass JPA stream-lined & amp; performant - jedes einzelne Objekt, das in der Datenbank persistiert, muss nicht mit einem Abruf des Objektstatus vorangegangen werden, um festzustellen, ob / was eingefügt / aktualisiert werden soll. Der JPA-Persistenzkontextobjektstatus enthält bereits genügend Details, um dies zu bestimmen.

Ihr Problem besteht darin, dass Sie neue Entitätsinstanzen haben, die Sie anwenden möchten als ob sie getrennt wurden - und das ist nicht die JPA-Art.

SaveOrUpdate ist eine proprietäre Hibernate-Operation - wenn eine Entität eine Identität hat, wird sie aktualisiert, aber wenn sie keine Entität hat, wird sie eingefügt.

Aus einer Perspektive Ruhezustand - ja, die Zusammenführung gefolgt von saveOrUpdate kann theoretisch zum Verknüpfen von transienten Objekten (Xstream-Streaming) mit persistent verwendet werden, aber es kann Einschränkungen in Verbindung mit JPA-Operationen haben. saveOrUpdate DOES voraus jedes Objekt persist der Datenbank mit einem Abruf zu bestimmen, ob / was zu fügen / zu aktualisieren - es ist schlau, aber es ist nicht JPA und es ist nicht die leistungsfähigste. Sie sollten in der Lage sein, dies mit einiger Sorgfalt und der richtigen Konfiguration zu bewerkstelligen - und im Konfliktfall statt mit JPA-Operationen den Ruhezustand zu verwenden.

  

Ich erhalte Fehler wie:

     

org.hibernate.ObjectDeletedException: Das gelöschte Objekt wird erneut gespeichert   durch Kaskadierung (entferntes Objekt aus Assoziationen entfernen):   [com ....... SomeObject # 353296]

Ich glaube, dass dies durch zwei Faktoren verursacht werden kann:

  • Irgendwo in Ihrem (Xstream-erstellten) Objektdiagramm fehlt eine untergeordnete Entitätsinstanz, die bei einem (kaskadierten) Abrufen mit JPA vorhanden wäre: Dies führt zu einem Objekt-Löschen
  • irgendwo anders in Ihnen (Xstream-erstellt) Objektdiagramm, ist diese gleiche Kind-Entität vorhanden: Dies gibt das Objekt wieder gespeichert

    Wie debugge ich das: (a) erstelle das Objektgraph von Xstream und drucke es IN FULL aus - jede Entität, jedes Feld; (b) Laden des gleichen Objektgraphen über JPA, Kaskadieren des Abrufs von der obersten Entität & amp; Drucke es IN FULL aus - jede Entität, jedes Feld (c) vergleiche die beiden - fehlt etwas in (a), das in (b) vorhanden ist?

  

Gibt es einen Weg, das zu erreichen, was ich tun will, ohne zu müssen?   das persistente Objekt in der Sitzung, und ändern Sie das anstelle von   Modifizieren der Transienten und versuchen, das zu speichern und überschreiben   bestehende persistente?

Über den gerade vorgeschlagenen / debug / fix - hoffentlich.

ODER mein Brute-Force-Vorschlag, um diesen Fehler (dummerweise) zu umgehen (verlangsamt die Leistung jedoch ein wenig): Nachdem Sie IDs im Objektdiagramm ausgefüllt haben, rufen Sie EntityManager.clear () auf, DANN fahren Sie mit merge () und fort saveOrUpdate (). Aber UNIT TEST die DB-Ergebnisse - um sicherzustellen, dass Sie nicht etwas Wichtiges übersehen haben, wenn Sie Ihren Xstream-Graphen gefüllt haben.

Zum Testen / als letzten Ausweg versuchen Sie saveOrUpdate () ohne merge (), aber Sie müssen dann den Entity-Manager deaktivieren, um Hibernate-Exceptions wie NonUniqueObjectException zu vermeiden.

Lassen Sie mich wissen, wenn Sie mehr erfahren / mehr Informationen haben B ^)

    
Glen Best 18.03.2013 05:09
quelle
1
%Vor%

Die Zusammenführung () sollte idealerweise für Sie arbeiten, da Sie sich tatsächlich mit einem losgelösten Objekt beschäftigen. Da Sie ids im 'transObj' vor dem Aufruf von merge setzen, würde Hibernate sie als getrennt (nicht vorübergehend) betrachten.

Ich denke, das Problem mit Ihrem Code ist, dass der Hibernate ausgelöst wird.

In Ihrem Code laden Sie das 'persistObj' aus der Datenbank. Jetzt hält Hibernate dieses "persistObj" in der Sitzung. Sie setzen dann einige der IDs von 'persistObj' in 'transObj' und rufen dann Merge auf. Einige der untergeordneten Objekte in 'persistObj' und 'transObj' haben die gleichen IDs, der Winterschlaf wird durcheinander gebracht.

%Vor%

Versuchen Sie, die session.clear () nach dem Laden von 'persistObj' aufzurufen, damit der Ruhezustand das persistObj entfernt und nur Ihr losgelöstes Objekt berücksichtigt.

%Vor%     
Sashi 18.03.2013 18:06
quelle