So beheben Sie den Fehler im Ruhezustand: "Objekt verweist auf eine nicht gespeicherte vorübergehende Instanz - Speichern Sie die vorübergehende Instanz vor dem Löschen"
610
Beim Speichern des Objekts im Ruhezustand wird folgende Fehlermeldung angezeigt
object references an unsaved transient instance - save the transient instance before flushing
Im Suchkontext ist dieser Fehler? ist es mit oder ohne transiente Variable?
Vijay
Antworten:
803
Sie sollten cascade="all"(wenn Sie XML verwenden) oder cascade=CascadeType.ALL(wenn Sie Anmerkungen verwenden) in Ihre Sammlungszuordnung aufnehmen.
Dies liegt daran, dass Sie eine Sammlung in Ihrer Entität haben und diese Sammlung ein oder mehrere Elemente enthält, die nicht in der Datenbank vorhanden sind. Indem Sie die oben genannten Optionen angeben, weisen Sie den Ruhezustand an, sie beim Speichern des übergeordneten Elements in der Datenbank zu speichern.
Ist das nicht implizit? Möchten Sie nicht immer, dass der Ruhezustand sie rettet?
Marcus Leon
29
@Marcus - nein, das ist es nicht. Möglicherweise möchten Sie sie manuell behandeln.
Bozho
5
Bozho hat recht. Ich bin auf Umstände gestoßen, in denen ich Sammlungen hatte, die ich aufgrund ihrer Größe manuell verwalten wollte, oder aufgrund von Geschäftsregeln, nach denen nicht alle Objekte in einer Sammlung gleichzeitig gespeichert werden können.
Alex Marshall
26
Es passiert nicht nur für Sammlungen, sondern auch für einfache Eins-zu-Eins-Zuordnungen
Sebastien Lorber
12
Wäre es nicht besser, mit CascadeType.PERSIST zu beginnen und persist zum Speichern zu verwenden?
Sergii Shevchyk
248
Ich glaube, dies könnte nur eine wiederholte Antwort sein, aber nur um dies zu verdeutlichen, habe ich dies sowohl auf einem @OneToOneMapping als auch auf einem @OneToMany. In beiden Fällen war es die Tatsache, dass das ChildObjekt , das ich hinzugefügt habe, Parentnoch nicht in der Datenbank gespeichert war. Wenn ich also das Childzum hinzufügte Parentund dann das speicherte Parent, warf Hibernate die "object references an unsaved transient instance - save the transient instance before flushing"Nachricht beim Speichern des übergeordneten Elements.
Das Hinzufügen cascade = {CascadeType.ALL}des Parent'sVerweises auf Childdas Problem wurde in beiden Fällen gelöst. Dies rettete das Childund das Parent.
Entschuldigen Sie die wiederholten Antworten, ich wollte sie nur weiter klären.
Was ist, wenn ich keine @ OneToOne-Beziehung kaskadieren möchte? Wie kann ich beim erstmaligen Erstellen beider Objekte eines in der Datenbank speichern, ohne die Ausnahme auszulösen?
Xtian
4
Was ist, wenn ich das Kind für einige Fälle und nicht für andere retten möchte?
Omaruchan
@xtian: Nun, dann müssen Sie sich um die richtige Reihenfolge beim Speichern in der Datenbank kümmern, indem Sie die Objekte mit einem EntityManager beibehalten. Im Grunde sagen Sie einfach em.persist (object1); em.persist (object2); usw.
kaba713
Ich habe dieses Problem speziell bei der Verwendung von @Inheritance erhalten. In diesem Fall hat TABLE_PER_CLASS auf eine Unterklasse verwiesen. CascadeType.ALL hat das Problem behoben.
Jim ReesPotter
Oder Sie haben Ihr Entitätsobjekt mit erstellt new MyEntity(ohne es mit der Datenbank zu synchronisieren - Leeren), anstatt seine synchronisierte Instanz aus der Datenbank abzurufen. Wenn Sie mit dieser Instanz Abfragen im Ruhezustand durchführen, werden Sie darüber informiert, dass sich das, was Sie in der Datenbank erwarten, von dem unterscheidet, was Sie im Speicher Ihrer App haben. In diesem Fall - synchronisieren Sie einfach Ihre Entitätsinstanz aus der Datenbank und verwenden Sie sie. Dann wird kein CascadeType.ALL benötigt.
Zon
67
Dies geschieht beim Speichern eines Objekts, wenn Hibernate der Ansicht ist, dass ein Objekt gespeichert werden muss, das dem Objekt zugeordnet ist, das Sie speichern.
Ich hatte dieses Problem und wollte keine Änderungen am referenzierten Objekt speichern, daher wollte ich, dass der Kaskadentyp NONE ist.
Der Trick besteht darin, sicherzustellen, dass ID und VERSION im referenzierten Objekt so festgelegt sind, dass Hibernate nicht glaubt, dass das referenzierte Objekt ein neues Objekt ist, das gespeichert werden muss. Das hat bei mir funktioniert.
Durchsuchen Sie alle Beziehungen in der Klasse, die Sie speichern, um die zugeordneten Objekte (und die zugeordneten Objekte der zugeordneten Objekte) zu ermitteln, und stellen Sie sicher, dass ID und VERSION in allen Objekten des Objektbaums festgelegt sind.
Dieser Kommentar hat mich auf den richtigen Weg gebracht. Ich habe eine neue Instanz des Elternteils einer Eigenschaft seines Kindes zugewiesen. Also dachte NH, es seien verschiedene Fälle.
Elvin
2
Ja. Dies geschieht beispielsweise, wenn die ID des zugeordneten Objekts nicht enthalten ist (z. B. wurde sie von @JsonIgnore ignoriert). Der Ruhezustand hat keine Möglichkeit, die zugeordnete Entität zu identifizieren, daher möchte er sie speichern.
Rori Stumpf
36
Einführung
Wie ich in diesem Artikel bei Verwendung von JPA und Hibernate erläutert habe , kann sich eine Entität in einem der folgenden 4 Zustände befinden:
Neu - Ein neu erstelltes Objekt, das noch nie einer Ruhezustandssitzung (auch als Persistenzkontext bezeichnet) zugeordnet wurde und keiner Datenbanktabellenzeile zugeordnet ist, befindet sich im Status Neu oder Transient.
Um persistent zu werden, müssen wir entweder die persistMethode explizit aufrufen oder den transitiven Persistenzmechanismus verwenden.
Persistent - Eine persistente Entität wurde einer Datenbanktabellenzeile zugeordnet und wird vom aktuell ausgeführten Persistenzkontext verwaltet.
Jede an einer solchen Entität vorgenommene Änderung wird erkannt und an die Datenbank weitergegeben (während der Sitzungsspülzeit).
Getrennt - Sobald der aktuell ausgeführte Persistenzkontext geschlossen ist, werden alle zuvor verwalteten Entitäten getrennt. Aufeinanderfolgende Änderungen werden nicht mehr verfolgt und es findet keine automatische Datenbanksynchronisierung statt.
Entfernt - Obwohl JPA verlangt, dass nur verwaltete Entitäten entfernt werden dürfen, kann Hibernate auch getrennte Entitäten löschen (jedoch nur über einen removeMethodenaufruf).
Übergänge des Entitätsstatus
Um ein Objekt von einem Zustand in den anderen zu bewegen, können Sie die verwenden persist, removeoder mergeMethoden.
Problem beheben
Das Problem, das Sie in Ihrer Frage beschreiben:
object references an unsaved transient instance - save the transient instance before flushing
wird verursacht, indem eine Entität im Status Neu einer Entität zugeordnet wird, die sich im Status Verwaltet befindet .
Dies kann passieren, wenn Sie eine untergeordnete Entität einer Eins-zu-Viele-Sammlung in der übergeordneten Entität zuordnen und die Sammlung keine cascadeÜbergänge des Entitätsstatus ausführt.
Wie ich in diesem Artikel erklärt habe , können Sie dies beheben, indem Sie der Entitätszuordnung, die diesen Fehler ausgelöst hat, wie folgt eine Kaskade hinzufügen:
Damit die Kaskade nun bidirektional ordnungsgemäß funktioniert, müssen Sie außerdem sicherstellen, dass die übergeordneten und untergeordneten Zuordnungen synchron sind.
In diesem Artikel erfahren Sie mehr darüber, wie Sie dieses Ziel am besten erreichen können.
In einer @ManyToManyZuordnung können Sie den Übergang des Löschentitätsstatus von einer übergeordneten zu einer anderen übergeordneten Entität nicht verwenden CascadeType.ALLoder übertragen orphanRemoval.
Daher @ManyToManykaskadieren Sie für Assoziationen normalerweise die Operationen CascadeType.PERSISToder CascadeType.MERGE. Alternativ können Sie das auf DETACHoder erweitern REFRESH.
Weitere Informationen zum besten Zuordnen einer @ManyToManyZuordnung finden Sie auch in diesem Artikel .
Dies sollte die akzeptierte Antwort sein. CascadeType.ALL ist zu breit
Lilalinux
5
Ab Hibernate 5.2.8 scheint es keine Möglichkeit zu geben, mit JPA-Annotationen den gleichen Effekt zu erzielen. Zum Beispiel @ManyToMany(cascade={PERSIST, MERGE, REFRESH, DETACH})kaskadiert (alle außer REMOVE) keine Updates wie bei Hibernate CascadeType.SAVE_UPDATE.
Jcsahnwaldt sagt GoFundMonica
25
In meinem Fall wurde es dadurch verursacht, dass ich nicht CascadeTypeauf der @ManyToOneSeite der bidirektionalen Beziehung stand. Genauer gesagt hatte ich CascadeType.ALLauf der @OneToManySeite und hatte es nicht an @ManyToOne. Hinzufügen CascadeType.ALLzu@ManyToOne um das Problem beheben.
Eins-zu-viele- Seite:
Wenn ich es auf diese Weise mache und die übergeordnete Entität speichere, befinden sich in meiner übergeordneten Tabelle zwei Einfügungen, die zwei Zeilen umfassen. Ich denke, es liegt daran, dass wir sowohl übergeordnete als auch untergeordnete Entitäten kaskadieren?
Programmierer
18
Dies trat bei mir auf, als eine Entität beibehalten wurde, in der der vorhandene Datensatz in der Datenbank einen NULL-Wert für das mit @Version annotierte Feld hatte (für optimistisches Sperren). Das Aktualisieren des NULL-Werts auf 0 in der Datenbank hat dies korrigiert.
Dies sollte eine neue Frage sein und als Fehler hinzugefügt werden, zumindest als irreführende Ausnahme. Dies stellte sich als Ursache für mein Problem heraus.
BML
Dies behebt mein Problem
Jad Chahine
11
Dies ist nicht der einzige Grund für den Fehler. Ich bin gerade auf einen Tippfehler in meiner Codierung gestoßen, bei dem meiner Meinung nach ein Wert für eine Entität festgelegt wurde, die bereits gespeichert wurde.
X x2 =new X();
x.setXid(memberid);// Error happened here - x was a previous global entity I created earlier
Y.setX(x2);
Ich habe den Fehler entdeckt, indem ich genau herausgefunden habe, welche Variable den Fehler verursacht hat (in diesem Fall String xid). Ich habe einen catchCodeblock verwendet, der die Entität gespeichert und die Spuren gedruckt hat.
{
code block that performed the operation
}catch(Exception e){
e.printStackTrace();// put a break-point here and inspect the 'e'return ERROR;}
Ähnliches Problem wie bei mir. Nachdem ich die Entität lokal neu geladen, die Eigenschaft festgelegt und dann gespeichert hatte, funktionierte sie einwandfrei.
CsBalazsHungary
8
Nicht verwenden, Cascade.Allbis Sie wirklich müssen. Roleund Permissionhaben bidirektionale manyToManyBeziehung. Dann würde der folgende Code gut funktionieren
Permission p =newPermission();
p.setName("help");Permission p2 =newPermission();
p2.setName("self_info");
p =(Permission)crudRepository.save(p);// returned p has id filled in.
p2 =(Permission)crudRepository.save(p2);// so does p2.Role role =newRole();
role.setAvailable(true);
role.setDescription("a test role");
role.setRole("admin");List<Permission> pList =newArrayList<Permission>();
pList.add(p);
pList.add(p2);
role.setPermissions(pList);
crudRepository.save(role);
Wenn das Objekt nur ein "neues" Objekt ist, wird derselbe Fehler ausgegeben.
Ist 100% korrekt, ist die Cascade.All die faule Lösung und sollte nur bei Bedarf angewendet werden. Wenn die Entität bereits vorhanden ist, überprüfen Sie zunächst, ob sie im aktuellen Entitätsmanager geladen ist. Wenn nicht, laden Sie sie.
Renato Mendes
7
Wenn Ihre Sammlung nullbar ist, versuchen Sie einfach: object.SetYouColection(null);
Das war total mein Problem. Ich hätte nie gedacht, dass ich es manuell auf null setzen muss.
Deadron
Dies war auch mein Problem. Ich habe keine Sammlung verwendet, also habe ich dies zuerst nicht versucht, aber ich habe mein Objekt auf null gesetzt und jetzt funktioniert es.
Futter
5
Um meine 2 Cent hinzuzufügen, habe ich das gleiche Problem, wenn ich versehentlich nullals ID sende . Der folgende Code zeigt mein Szenario (und OP hat kein bestimmtes Szenario erwähnt) .
Employee emp =newEmployee();
emp.setDept(newDept(deptId));// --> when deptId PKID is null, same error will be thrown// calls to other setters...
em.persist(emp);
Hier setze ich die vorhandene Abteilungs-ID auf eine neue Mitarbeiterinstanz, ohne zuerst die Abteilungsentität zu erhalten, da ich nicht möchte, dass eine andere ausgewählte Abfrage ausgelöst wird.
In einigen Szenarien kommt deptIdPKID alsnull von der aufrufenden Methode und ich den gleichen Fehler.
Ich habe ein ähnliches Problem. Ich erhalte die Ausnahme, wenn meine deptID 0 ist. Jeder andere Wert größer als 0 funktioniert. Komisch ist, dass ich eine Abteilung mit id = 0 habe.
Gustavo
5
Dieses Problem trat mir auf, als ich eine neue Entität und eine zugehörige Entität in einer als gekennzeichneten Methode erstellte und @Transactionalvor dem Speichern eine Abfrage durchführte. Ex
@Transactionalpublic someService(){Entity someEntity =newEntity();AssocaiatedEntity associatedEntity =newAssocaitedEntity();
someEntity.setAssociatedEntity(associatedEntity);
associatedEntity.setEntity(someEntity);// Performing any query was causing hibernate to attempt to persist the new entity. It would then throw an exception
someDao.getSomething();
entityDao.create(someEntity);}
Um dies zu beheben, habe ich die Abfrage durchgeführt, bevor ich die neue Entität erstellt habe.
Neben allen anderen guten Antworten kann dies passieren, wenn Sie mergeein Objekt beibehalten und versehentlich vergessen, die zusammengeführte Referenz des Objekts in der übergeordneten Klasse zu verwenden. Betrachten Sie das folgende Beispiel
merge(A);
B.setA(A);
persist(B);
In diesem Fall führen Sie zusammen A, vergessen jedoch, das zusammengeführte Objekt von zu verwenden A. Um das Problem zu lösen, müssen Sie den Code wie folgt umschreiben.
A=merge(A);//difference is here
B.setA(A);
persist(B);
Ich war auch mit der gleichen Situation konfrontiert. Durch Setzen der folgenden Anmerkung über der Eigenschaft wurde die angeforderte Ausnahme behoben.
Die Ausnahme, mit der ich konfrontiert war.
Exception in thread "main" java.lang.IllegalStateException: org.hibernate.TransientObjectException: object references an unsaved transient instance - save the transient instance before flushing: com.model.Car_OneToMany
Um zu überwinden, die Anmerkung, die ich verwendet habe.
Was hat Hibernate dazu gebracht, die Ausnahme zu werfen:
Diese Ausnahme wird an Ihrer Konsole ausgelöst, da das untergeordnete Objekt, das ich an das übergeordnete Objekt anhänge, derzeit nicht in der Datenbank vorhanden ist.
Durch die Bereitstellung @OneToMany(cascade = {CascadeType.ALL})wird Hibernate angewiesen, sie in der Datenbank zu speichern, während das übergeordnete Objekt gespeichert wird.
object references an unsaved transient instance - save the transient instance before flushing
auftreten wird auch , wenn Sie versuchen , eine Einheit mit einem Verweis auf ein anderes Unternehmen zu beharren / fusionieren , die sich zufällig abgelöst .
Die Methode setNewPassword () erstellt einen PasswordHistory-Datensatz und fügt ihn der Verlaufssammlung in User hinzu. Da die Anweisung create () für das übergeordnete Element noch nicht ausgeführt wurde, wurde versucht, sie in einer Sammlung einer Entität zu speichern, die noch nicht erstellt wurde. Alles, was ich tun musste, um das Problem zu beheben, war, den Aufruf von setNewPassword () nach dem Aufruf von create () zu verschieben.
Es gibt eine andere Möglichkeit, die diesen Fehler im Ruhezustand verursachen kann. Möglicherweise legen Sie einen nicht gespeicherten Verweis Ihres Objekts Aauf eine angehängte Entität fest Bund möchten das Objekt beibehalten C. Auch in diesem Fall erhalten Sie den oben genannten Fehler.
Ich denke, das liegt daran, dass Sie versucht haben, ein Objekt zu persistieren, das einen Verweis auf ein anderes Objekt hat, das noch nicht persistiert ist, und deshalb auf der "DB-Seite" versuchen, einen Verweis auf eine Zeile zu setzen, die nicht existiert
Eine einfache Möglichkeit, dieses Problem zu lösen, besteht darin, beide Entitäten zu speichern. Speichern Sie zuerst die untergeordnete Entität und dann die übergeordnete Entität. Da die übergeordnete Entität für den Fremdschlüsselwert von der untergeordneten Entität abhängt.
Unten einfache Prüfung einer Eins-zu-Eins-Beziehung
insert into Department(name, numOfemp,Depno) values (?,?,?)Hibernate: insert into Employee(SSN, dep_Depno, firstName, lastName, middleName, empno) values (?,?,?,?,?,?)Session session=sf.openSession();
session.beginTransaction();
session.save(dep);
session.save(emp);
Es ist das Gegenteil - die untergeordnete Entität enthält den FK-Wert und hängt vom übergeordneten Element ab. Sie müssen also zuerst das übergeordnete Element speichern! Im Codeblock haben Sie es richtig.
17.
0
Eine mögliche Fehlerursache ist das Nichtvorhandensein der Einstellung des Werts der übergeordneten Entität. Für eine Beziehung zwischen Abteilung und Mitarbeitern müssen Sie dies beispielsweise schreiben, um den Fehler zu beheben:
Department dept =(Department)session.load(Department.class, dept_code);// dept_code is from the jsp form which you get in the controller with @RequestParam String department
employee.setDepartment(dept);
Es gibt so viele Möglichkeiten für diesen Fehler. Einige andere Möglichkeiten gibt es auch auf Seite hinzufügen oder Seite bearbeiten. In meinem Fall habe ich versucht, ein Objekt AdvanceSalary zu speichern. Das Problem ist, dass beim Bearbeiten die AdvanceSalary employee.employee_id null ist. Da ich beim Bearbeiten die employee.employee_id nicht festgelegt habe. Ich habe ein verstecktes Feld gemacht und es gesetzt. Mein Code funktioniert absolut gut.
Ich war mit dieser Ausnahme konfrontiert, als ich das übergeordnete Objekt nicht beibehalten habe, aber das Kind gerettet habe. Um das Problem zu beheben, habe ich in derselben Sitzung sowohl das untergeordnete als auch das übergeordnete Objekt beibehalten und CascadeType.ALL für das übergeordnete Objekt verwendet.
Fall 1: Ich habe diese Ausnahme erhalten, als ich versucht habe, ein übergeordnetes Element zu erstellen und diesen übergeordneten Verweis auf sein untergeordnetes Element und dann eine andere DELETE / UPDATE-Abfrage (JPQL) zu speichern. Ich spüle () einfach die neu erstellte Entität nach dem Erstellen des übergeordneten Elements und nach dem Erstellen des untergeordneten Elements unter Verwendung derselben übergeordneten Referenz. Es hat bei mir funktioniert.
In dem obigen Fall, in dem Eltern (Referenz) und Kind (ReferenzAdditionalDetails) eine OneToOne-Beziehung haben und wenn Sie versuchen, eine Referenzentität und dann ihr Kind (ReferenzAdditionalDetails) zu erstellen, erhalten Sie dieselbe Ausnahme. Um die Ausnahme zu vermeiden, müssen Sie für die untergeordnete Klasse null setzen und dann die übergeordnete Klasse erstellen. (Beispielcode)
Mein Problem @BeforeEachhing mit JUnit zusammen. Und selbst wenn ich die zugehörigen Entitäten gespeichert habe (in meinem Fall@ManyToOne ) , habe ich den gleichen Fehler erhalten.
Das Problem hängt irgendwie mit der Sequenz zusammen, die ich in meinem Elternteil habe. Wenn ich diesem Attribut den Wert zuordne, ist das Problem gelöst.
Ex. Wenn ich die Entitätsfrage habe, die einige Kategorien (eine oder mehrere) haben kann, und die Entitätsfrage eine Sequenz hat:
Machen Sie einfach den Konstruktor Ihres Mappings in Ihrer Basisklasse. Wenn Sie beispielsweise eine Eins-zu-Eins-Beziehung in Entität A und Entität B wünschen, wenn Sie A als Basisklasse verwenden, muss A einen Konstruktor haben, der B als Argument hat.
Antworten:
Sie sollten
cascade="all"
(wenn Sie XML verwenden) odercascade=CascadeType.ALL
(wenn Sie Anmerkungen verwenden) in Ihre Sammlungszuordnung aufnehmen.Dies liegt daran, dass Sie eine Sammlung in Ihrer Entität haben und diese Sammlung ein oder mehrere Elemente enthält, die nicht in der Datenbank vorhanden sind. Indem Sie die oben genannten Optionen angeben, weisen Sie den Ruhezustand an, sie beim Speichern des übergeordneten Elements in der Datenbank zu speichern.
quelle
Ich glaube, dies könnte nur eine wiederholte Antwort sein, aber nur um dies zu verdeutlichen, habe ich dies sowohl auf einem
@OneToOne
Mapping als auch auf einem@OneToMany
. In beiden Fällen war es die Tatsache, dass dasChild
Objekt , das ich hinzugefügt habe,Parent
noch nicht in der Datenbank gespeichert war. Wenn ich also dasChild
zum hinzufügteParent
und dann das speicherteParent
, warf Hibernate die"object references an unsaved transient instance - save the transient instance before flushing"
Nachricht beim Speichern des übergeordneten Elements.Das Hinzufügen
cascade = {CascadeType.ALL}
desParent's
Verweises aufChild
das Problem wurde in beiden Fällen gelöst. Dies rettete dasChild
und dasParent
.Entschuldigen Sie die wiederholten Antworten, ich wollte sie nur weiter klären.
quelle
new MyEntity
(ohne es mit der Datenbank zu synchronisieren - Leeren), anstatt seine synchronisierte Instanz aus der Datenbank abzurufen. Wenn Sie mit dieser Instanz Abfragen im Ruhezustand durchführen, werden Sie darüber informiert, dass sich das, was Sie in der Datenbank erwarten, von dem unterscheidet, was Sie im Speicher Ihrer App haben. In diesem Fall - synchronisieren Sie einfach Ihre Entitätsinstanz aus der Datenbank und verwenden Sie sie. Dann wird kein CascadeType.ALL benötigt.Dies geschieht beim Speichern eines Objekts, wenn Hibernate der Ansicht ist, dass ein Objekt gespeichert werden muss, das dem Objekt zugeordnet ist, das Sie speichern.
Ich hatte dieses Problem und wollte keine Änderungen am referenzierten Objekt speichern, daher wollte ich, dass der Kaskadentyp NONE ist.
Der Trick besteht darin, sicherzustellen, dass ID und VERSION im referenzierten Objekt so festgelegt sind, dass Hibernate nicht glaubt, dass das referenzierte Objekt ein neues Objekt ist, das gespeichert werden muss. Das hat bei mir funktioniert.
Durchsuchen Sie alle Beziehungen in der Klasse, die Sie speichern, um die zugeordneten Objekte (und die zugeordneten Objekte der zugeordneten Objekte) zu ermitteln, und stellen Sie sicher, dass ID und VERSION in allen Objekten des Objektbaums festgelegt sind.
quelle
Einführung
Wie ich in diesem Artikel bei Verwendung von JPA und Hibernate erläutert habe , kann sich eine Entität in einem der folgenden 4 Zustände befinden:
Neu - Ein neu erstelltes Objekt, das noch nie einer Ruhezustandssitzung (auch als Persistenzkontext bezeichnet) zugeordnet wurde und keiner Datenbanktabellenzeile zugeordnet ist, befindet sich im Status Neu oder Transient.
Um persistent zu werden, müssen wir entweder die
persist
Methode explizit aufrufen oder den transitiven Persistenzmechanismus verwenden.Persistent - Eine persistente Entität wurde einer Datenbanktabellenzeile zugeordnet und wird vom aktuell ausgeführten Persistenzkontext verwaltet.
Jede an einer solchen Entität vorgenommene Änderung wird erkannt und an die Datenbank weitergegeben (während der Sitzungsspülzeit).
Getrennt - Sobald der aktuell ausgeführte Persistenzkontext geschlossen ist, werden alle zuvor verwalteten Entitäten getrennt. Aufeinanderfolgende Änderungen werden nicht mehr verfolgt und es findet keine automatische Datenbanksynchronisierung statt.
Entfernt - Obwohl JPA verlangt, dass nur verwaltete Entitäten entfernt werden dürfen, kann Hibernate auch getrennte Entitäten löschen (jedoch nur über einen
remove
Methodenaufruf).Übergänge des Entitätsstatus
Um ein Objekt von einem Zustand in den anderen zu bewegen, können Sie die verwenden
persist
,remove
odermerge
Methoden.Problem beheben
Das Problem, das Sie in Ihrer Frage beschreiben:
wird verursacht, indem eine Entität im Status Neu einer Entität zugeordnet wird, die sich im Status Verwaltet befindet .
Dies kann passieren, wenn Sie eine untergeordnete Entität einer Eins-zu-Viele-Sammlung in der übergeordneten Entität zuordnen und die Sammlung keine
cascade
Übergänge des Entitätsstatus ausführt.Wie ich in diesem Artikel erklärt habe , können Sie dies beheben, indem Sie der Entitätszuordnung, die diesen Fehler ausgelöst hat, wie folgt eine Kaskade hinzufügen:
Der
@OneToOne
VereinDer
@OneToMany
VereinAuch hier
CascadeType.ALL
ist das für die bidirektionalen@OneToMany
Assoziationen geeignet .Damit die Kaskade nun bidirektional ordnungsgemäß funktioniert, müssen Sie außerdem sicherstellen, dass die übergeordneten und untergeordneten Zuordnungen synchron sind.
Der
@ManyToMany
VereinIn einer
@ManyToMany
Zuordnung können Sie den Übergang des Löschentitätsstatus von einer übergeordneten zu einer anderen übergeordneten Entität nicht verwendenCascadeType.ALL
oder übertragenorphanRemoval
.Daher
@ManyToMany
kaskadieren Sie für Assoziationen normalerweise die OperationenCascadeType.PERSIST
oderCascadeType.MERGE
. Alternativ können Sie das aufDETACH
oder erweiternREFRESH
.quelle
Oder wenn Sie minimale "Kräfte" verwenden möchten (z. B. wenn Sie keine Kaskadenlöschung wünschen), um das zu erreichen, was Sie wollen, verwenden Sie
quelle
@ManyToMany(cascade={PERSIST, MERGE, REFRESH, DETACH})
kaskadiert (alle außer REMOVE) keine Updates wie bei HibernateCascadeType.SAVE_UPDATE
.In meinem Fall wurde es dadurch verursacht, dass ich nicht
CascadeType
auf der@ManyToOne
Seite der bidirektionalen Beziehung stand. Genauer gesagt hatte ichCascadeType.ALL
auf der@OneToMany
Seite und hatte es nicht an@ManyToOne
. HinzufügenCascadeType.ALL
zu@ManyToOne
um das Problem beheben. Eins-zu-viele- Seite:Viele-zu-eins-Seite (verursachte das Problem)
Viele zu eins (durch Hinzufügen behoben
CascadeType.PERSIST
)quelle
Dies trat bei mir auf, als eine Entität beibehalten wurde, in der der vorhandene Datensatz in der Datenbank einen NULL-Wert für das mit @Version annotierte Feld hatte (für optimistisches Sperren). Das Aktualisieren des NULL-Werts auf 0 in der Datenbank hat dies korrigiert.
quelle
Dies ist nicht der einzige Grund für den Fehler. Ich bin gerade auf einen Tippfehler in meiner Codierung gestoßen, bei dem meiner Meinung nach ein Wert für eine Entität festgelegt wurde, die bereits gespeichert wurde.
Ich habe den Fehler entdeckt, indem ich genau herausgefunden habe, welche Variable den Fehler verursacht hat (in diesem Fall
String xid
). Ich habe einencatch
Codeblock verwendet, der die Entität gespeichert und die Spuren gedruckt hat.quelle
Nicht verwenden,
Cascade.All
bis Sie wirklich müssen.Role
undPermission
haben bidirektionalemanyToMany
Beziehung. Dann würde der folgende Code gut funktionierenWenn das Objekt nur ein "neues" Objekt ist, wird derselbe Fehler ausgegeben.
quelle
Wenn Ihre Sammlung nullbar ist, versuchen Sie einfach:
object.SetYouColection(null);
quelle
Um meine 2 Cent hinzuzufügen, habe ich das gleiche Problem, wenn ich versehentlich
null
als ID sende . Der folgende Code zeigt mein Szenario (und OP hat kein bestimmtes Szenario erwähnt) .Hier setze ich die vorhandene Abteilungs-ID auf eine neue Mitarbeiterinstanz, ohne zuerst die Abteilungsentität zu erhalten, da ich nicht möchte, dass eine andere ausgewählte Abfrage ausgelöst wird.
In einigen Szenarien kommt
deptId
PKID alsnull
von der aufrufenden Methode und ich den gleichen Fehler.Achten Sie also auf
null
Werte für die PK-IDquelle
Dieses Problem trat mir auf, als ich eine neue Entität und eine zugehörige Entität in einer als gekennzeichneten Methode erstellte und
@Transactional
vor dem Speichern eine Abfrage durchführte. ExUm dies zu beheben, habe ich die Abfrage durchgeführt, bevor ich die neue Entität erstellt habe.
quelle
Neben allen anderen guten Antworten kann dies passieren, wenn Sie
merge
ein Objekt beibehalten und versehentlich vergessen, die zusammengeführte Referenz des Objekts in der übergeordneten Klasse zu verwenden. Betrachten Sie das folgende BeispielIn diesem Fall führen Sie zusammen
A
, vergessen jedoch, das zusammengeführte Objekt von zu verwendenA
. Um das Problem zu lösen, müssen Sie den Code wie folgt umschreiben.quelle
Ich bekomme diesen Fehler, wenn ich benutze
aber es funktioniert ohne problem, wenn ich benutze
quelle
Ich war auch mit der gleichen Situation konfrontiert. Durch Setzen der folgenden Anmerkung über der Eigenschaft wurde die angeforderte Ausnahme behoben.
Die Ausnahme, mit der ich konfrontiert war.
Um zu überwinden, die Anmerkung, die ich verwendet habe.
Was hat Hibernate dazu gebracht, die Ausnahme zu werfen:
Diese Ausnahme wird an Ihrer Konsole ausgelöst, da das untergeordnete Objekt, das ich an das übergeordnete Objekt anhänge, derzeit nicht in der Datenbank vorhanden ist.
Durch die Bereitstellung
@OneToMany(cascade = {CascadeType.ALL})
wird Hibernate angewiesen, sie in der Datenbank zu speichern, während das übergeordnete Objekt gespeichert wird.quelle
Der Vollständigkeit halber: A.
mit Nachricht
auftreten wird auch , wenn Sie versuchen , eine Einheit mit einem Verweis auf ein anderes Unternehmen zu beharren / fusionieren , die sich zufällig abgelöst .
quelle
Ein weiterer möglicher Grund: In meinem Fall habe ich versucht, das Kind vor dem Speichern des Elternteils auf einer brandneuen Entität zu retten.
Der Code war in einem User.java-Modell ungefähr so:
Die Methode setNewPassword () erstellt einen PasswordHistory-Datensatz und fügt ihn der Verlaufssammlung in User hinzu. Da die Anweisung create () für das übergeordnete Element noch nicht ausgeführt wurde, wurde versucht, sie in einer Sammlung einer Entität zu speichern, die noch nicht erstellt wurde. Alles, was ich tun musste, um das Problem zu beheben, war, den Aufruf von setNewPassword () nach dem Aufruf von create () zu verschieben.
quelle
Es gibt eine andere Möglichkeit, die diesen Fehler im Ruhezustand verursachen kann. Möglicherweise legen Sie einen nicht gespeicherten Verweis Ihres Objekts
A
auf eine angehängte Entität festB
und möchten das Objekt beibehaltenC
. Auch in diesem Fall erhalten Sie den oben genannten Fehler.quelle
Wenn Sie Spring Data JPA verwenden
@Transactional
, wird das Problem durch Hinzufügen von Anmerkungen zu Ihrer Service-Implementierung behoben.quelle
Ich denke, das liegt daran, dass Sie versucht haben, ein Objekt zu persistieren, das einen Verweis auf ein anderes Objekt hat, das noch nicht persistiert ist, und deshalb auf der "DB-Seite" versuchen, einen Verweis auf eine Zeile zu setzen, die nicht existiert
quelle
Eine einfache Möglichkeit, dieses Problem zu lösen, besteht darin, beide Entitäten zu speichern. Speichern Sie zuerst die untergeordnete Entität und dann die übergeordnete Entität. Da die übergeordnete Entität für den Fremdschlüsselwert von der untergeordneten Entität abhängt.
Unten einfache Prüfung einer Eins-zu-Eins-Beziehung
quelle
Eine mögliche Fehlerursache ist das Nichtvorhandensein der Einstellung des Werts der übergeordneten Entität. Für eine Beziehung zwischen Abteilung und Mitarbeitern müssen Sie dies beispielsweise schreiben, um den Fehler zu beheben:
quelle
Es gibt so viele Möglichkeiten für diesen Fehler. Einige andere Möglichkeiten gibt es auch auf Seite hinzufügen oder Seite bearbeiten. In meinem Fall habe ich versucht, ein Objekt AdvanceSalary zu speichern. Das Problem ist, dass beim Bearbeiten die AdvanceSalary employee.employee_id null ist. Da ich beim Bearbeiten die employee.employee_id nicht festgelegt habe. Ich habe ein verstecktes Feld gemacht und es gesetzt. Mein Code funktioniert absolut gut.
quelle
Ich war mit dieser Ausnahme konfrontiert, als ich das übergeordnete Objekt nicht beibehalten habe, aber das Kind gerettet habe. Um das Problem zu beheben, habe ich in derselben Sitzung sowohl das untergeordnete als auch das übergeordnete Objekt beibehalten und CascadeType.ALL für das übergeordnete Objekt verwendet.
quelle
Fall 1: Ich habe diese Ausnahme erhalten, als ich versucht habe, ein übergeordnetes Element zu erstellen und diesen übergeordneten Verweis auf sein untergeordnetes Element und dann eine andere DELETE / UPDATE-Abfrage (JPQL) zu speichern. Ich spüle () einfach die neu erstellte Entität nach dem Erstellen des übergeordneten Elements und nach dem Erstellen des untergeordneten Elements unter Verwendung derselben übergeordneten Referenz. Es hat bei mir funktioniert.
Fall 2:
Übergeordnete Klasse
Kinderklasse:
In dem obigen Fall, in dem Eltern (Referenz) und Kind (ReferenzAdditionalDetails) eine OneToOne-Beziehung haben und wenn Sie versuchen, eine Referenzentität und dann ihr Kind (ReferenzAdditionalDetails) zu erstellen, erhalten Sie dieselbe Ausnahme. Um die Ausnahme zu vermeiden, müssen Sie für die untergeordnete Klasse null setzen und dann die übergeordnete Klasse erstellen. (Beispielcode)
quelle
Mein Problem
@BeforeEach
hing mit JUnit zusammen. Und selbst wenn ich die zugehörigen Entitäten gespeichert habe (in meinem Fall@ManyToOne
) , habe ich den gleichen Fehler erhalten.Das Problem hängt irgendwie mit der Sequenz zusammen, die ich in meinem Elternteil habe. Wenn ich diesem Attribut den Wert zuordne, ist das Problem gelöst.
Ex. Wenn ich die Entitätsfrage habe, die einige Kategorien (eine oder mehrere) haben kann, und die Entitätsfrage eine Sequenz hat:
Ich muss den Wert zuweisen
question.setId(1L);
quelle
Machen Sie einfach den Konstruktor Ihres Mappings in Ihrer Basisklasse. Wenn Sie beispielsweise eine Eins-zu-Eins-Beziehung in Entität A und Entität B wünschen, wenn Sie A als Basisklasse verwenden, muss A einen Konstruktor haben, der B als Argument hat.
quelle