Ich habe im Wesentlichen einige Objekte in dieser Konfiguration (das reale Datenmodell ist etwas komplexer):
- A hat eine Viele-zu-Viele-Beziehung zu B. (B hat
inverse="true"
) - B hat eine Eins-zu-Eins-Beziehung zu C. (Ich habe
cascade
eingestellt auf"save-update"
) - C ist eine Art Typ- / Kategorietabelle.
Außerdem sollte ich wahrscheinlich erwähnen, dass die Primärschlüssel beim Speichern von der Datenbank generiert werden.
Bei meinen Daten treten manchmal Probleme auf, bei denen A eine Reihe verschiedener B-Objekte hat und diese B-Objekte auf dasselbe C-Objekt verweisen.
Wenn ich anrufe session.saveOrUpdate(myAObject)
, wird eine Fehlermeldung im Ruhezustand angezeigt, die besagt : "a different object with the same identifier value was already associated with the session: C"
. Ich weiß, dass der Ruhezustand nicht dasselbe Objekt zweimal in derselben Sitzung einfügen / aktualisieren / löschen kann, aber gibt es einen Weg, dies zu umgehen? Dies scheint nicht so ungewöhnlich zu sein.
Während meiner Untersuchung dieses Problems habe ich Leute gesehen, die die Verwendung von vorgeschlagen haben session.merge()
, aber wenn ich das tue, werden alle "widersprüchlichen" Objekte als leere Objekte in die Datenbank eingefügt, wobei alle Werte auf null gesetzt sind. Das wollen wir natürlich nicht.
[Bearbeiten] Eine andere Sache, die ich vergessen habe zu erwähnen, ist, dass (aus architektonischen Gründen, die außerhalb meiner Kontrolle liegen) jedes Lesen oder Schreiben in einer separaten Sitzung erfolgen muss.
Antworten:
Höchstwahrscheinlich, weil sich die B-Objekte nicht auf dieselbe Java C-Objektinstanz beziehen. Sie beziehen sich auf dieselbe Zeile in der Datenbank (dh denselben Primärschlüssel), sind jedoch unterschiedliche Kopien davon.
Was also passiert, ist, dass die Hibernate-Sitzung, die die Entitäten verwaltet, verfolgt, welches Java-Objekt der Zeile mit demselben Primärschlüssel entspricht.
Eine Möglichkeit wäre, sicherzustellen, dass die Entitäten von Objekten B, die auf dieselbe Zeile verweisen, tatsächlich auf dieselbe Objektinstanz von C verweisen. Alternativ können Sie die Kaskadierung für diese Mitgliedsvariable deaktivieren. Auf diese Weise ist C nicht erhalten, wenn B bestehen bleibt. Sie müssen C jedoch manuell separat speichern. Wenn C eine Typ- / Kategorietabelle ist, ist es wahrscheinlich sinnvoll, dies zu tun.
quelle
Stellen Sie einfach die Kaskade auf MERGE, das sollte den Trick machen.
quelle
Sie müssen nur eine Sache tun. Führen Sie
session_object.clear()
das neue Objekt aus und speichern Sie es. Dadurch wird die Sitzung (wie treffend benannt) gelöscht und das fehlerhafte doppelte Objekt aus Ihrer Sitzung entfernt.quelle
Ich stimme @Hemant Kumar zu, vielen Dank. Nach seiner Lösung habe ich mein Problem gelöst.
Beispielsweise:
Person.java
Dieser Code macht in meiner Anwendung immer einen Fehler:
A different object with the same identifier value was already associated with the session
Später stellte ich fest, dass ich vergessen hatte, meinen Primärschlüssel automatisch zu erhöhen!Meine Lösung besteht darin, diesen Code Ihrem Primärschlüssel hinzuzufügen:
quelle
Übertragen Sie die Aufgabe zum Zuweisen der Objekt-ID aus dem Ruhezustand zur Datenbank mithilfe von:
Dies löste das Problem für mich.
quelle
Dies bedeutet, dass Sie versuchen, mehrere Zeilen in Ihrer Tabelle mit dem Verweis auf dasselbe Objekt zu speichern.
Überprüfen Sie die ID-Eigenschaft Ihrer Entitätsklasse.
zu
quelle
Fügen Sie der Bean, die Sie einfügen, die Anmerkung @GeneratedValue hinzu.
quelle
Eine Möglichkeit, das oben genannte Problem zu lösen, besteht darin, das zu überschreiben
hashcode()
.Leeren Sie auch den Ruhezustand vor und nach dem Speichern.
Das explizite Festlegen des getrennten Objekts auf
null
hilft ebenfalls.quelle
Ich bin gerade auf diese Nachricht gestoßen, aber in C # -Code. Ich bin mir nicht sicher, ob es relevant ist (genau die gleiche Fehlermeldung).
Ich habe den Code mit Haltepunkten debuggt und einige Sammlungen durch private Mitglieder erweitert, während sich der Debugger an einem Haltepunkt befand. Nachdem der Code erneut ausgeführt wurde, ohne die Strukturen zu durchsuchen, verschwand die Fehlermeldung. Es scheint, als hätte NHibernate durch das Durchsuchen privater, faul geladener Sammlungen Dinge geladen, die zu diesem Zeitpunkt nicht geladen werden sollten (weil sie sich in privaten Mitgliedern befanden).
Der Code selbst ist in eine ziemlich komplizierte Transaktion eingebunden, die eine große Anzahl von Datensätzen und viele Abhängigkeiten als Teil dieser Transaktion aktualisieren kann (Importprozess).
Hoffentlich ein Hinweis für alle anderen, die auf das Problem stoßen.
quelle
Suchen Sie das Attribut "Cascade" im Ruhezustand und löschen Sie es. Wenn Sie "Cascade" verfügbar machen, werden andere Vorgänge (Speichern, Aktualisieren und Löschen) für andere Entitäten aufgerufen, die eine Beziehung zu verwandten Klassen haben. Es wird also der gleiche Identitätswert auftreten. Es hat bei mir funktioniert.
quelle
Ich hatte diesen Fehler einige Tage später und habe zu viel Zeit damit verbracht, diesen Fehler zu beheben.
Bevor ich diesen Fehler erhalte, habe ich den ID-Generierungstyp im OrderDetil-Objekt nicht erwähnt. Ohne die ID von Orderdetails zu generieren, wird die ID für jedes OrderDetail-Objekt als 0 beibehalten. das erklärte #jbx. Ja, das ist die beste Antwort. Dieses eine Beispiel, wie es passiert.
quelle
Versuchen Sie, den Code Ihrer Abfrage vorher zu platzieren. Das behebt mein Problem. zB ändern Sie dies:
dazu:
quelle
Möglicherweise legen Sie die Kennung des Objekts nicht fest, bevor Sie die Aktualisierungsabfrage aufrufen.
quelle
Ich bin auf das Problem gestoßen, weil die Generierung des Primärschlüssels falsch ist, wenn ich eine Zeile wie diese einfüge:
Ich ändere die ID-Generator-Klasse in Identität
quelle
In meinem Fall hat nur flush () nicht funktioniert. Ich musste nach flush () ein clear () verwenden.
quelle
Wenn Sie EntityRepository verwenden, verwenden Sie saveAndFlush anstelle von save
quelle
Wenn in meiner IDE eine Registerkarte für Ausdrücke geöffnet bleibt, die einen Ruhezustand auslöst, wird das Objekt aufgerufen, das diese Ausnahme verursacht. Ich habe versucht, dasselbe Objekt zu löschen. Außerdem hatte ich einen Haltepunkt beim Löschaufruf, der notwendig zu sein scheint, damit dieser Fehler auftritt. Durch einfaches Erstellen einer anderen Registerkarte für Ausdrücke als vordere Registerkarte oder Ändern der Einstellung, damit die Idee nicht an Haltepunkten anhält, wurde dieses Problem behoben.
quelle
Stellen Sie sicher, dass Ihre Entität mit allen zugeordneten Entitäten denselben Generierungstyp hat
Beispiel: UserRole
}}
Modul:
}}
Hauptentität mit Mapping
}}
quelle
Zusätzlich zu allen vorherigen Antworten eine mögliche Lösung für dieses Problem in einem Großprojekt, wenn Sie ein Wertobjekt für Ihre Klassen verwenden und das ID-Attribut nicht in der VO Transformer-Klasse festlegen.
quelle
Übernehmen Sie einfach die aktuelle Transaktion.
Jetzt können Sie eine weitere Transaktion starten und alles für die Entität tun
quelle