Beim Speichern des Objekts im Ruhezustand wird folgende Fehlermeldung angezeigt
object references an unsaved transient instance - save the transient instance before flushing
Beim Speichern des Objekts im Ruhezustand wird folgende Fehlermeldung angezeigt
object references an unsaved transient instance - save the transient instance before flushing
Antworten:
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.
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 das Child
Objekt , das ich hinzugefügt habe, Parent
noch nicht in der Datenbank gespeichert war. Wenn ich also das Child
zum hinzufügte Parent
und 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's
Verweises auf Child
das Problem wurde in beiden Fällen gelöst. Dies rettete das Child
und das Parent
.
Entschuldigen Sie die wiederholten Antworten, ich wollte sie nur weiter klären.
@OneToOne(cascade = {CascadeType.ALL})
@JoinColumn(name = "performancelog_id")
public PerformanceLog getPerformanceLog() {
return performanceLog;
}
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.
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).
Um ein Objekt von einem Zustand in den anderen zu bewegen, können Sie die verwenden persist
, remove
oder merge
Methoden.
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:
@OneToOne
Verein@OneToOne(
mappedBy = "post",
orphanRemoval = true,
cascade = CascadeType.ALL)
private PostDetails details;
Beachten Sie den
CascadeType.ALL
Wert, den wir für dascascade
Attribut hinzugefügt haben.
@OneToMany
Verein@OneToMany(
mappedBy = "post",
orphanRemoval = true,
cascade = CascadeType.ALL)
private List<Comment> comments = new ArrayList<>();
Auch 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.
In diesem Artikel erfahren Sie mehr darüber, wie Sie dieses Ziel am besten erreichen können.
@ManyToMany
Verein@ManyToMany(
mappedBy = "authors",
cascade = {
CascadeType.PERSIST,
CascadeType.MERGE
}
)
private List<Book> books = new ArrayList<>();
In einer @ManyToMany
Zuordnung können Sie den Übergang des Löschentitätsstatus von einer übergeordneten zu einer anderen übergeordneten Entität nicht verwenden CascadeType.ALL
oder übertragen orphanRemoval
.
Daher @ManyToMany
kaskadieren Sie für Assoziationen normalerweise die Operationen CascadeType.PERSIST
oder CascadeType.MERGE
. Alternativ können Sie das auf DETACH
oder erweitern REFRESH
.
Weitere Informationen zum besten Zuordnen einer
@ManyToMany
Zuordnung finden Sie auch in diesem Artikel .
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
import org.hibernate.annotations.Cascade;
import org.hibernate.annotations.CascadeType;
...
@Cascade({CascadeType.SAVE_UPDATE})
private Set<Child> children;
@ManyToMany(cascade={PERSIST, MERGE, REFRESH, DETACH})
kaskadiert (alle außer REMOVE) keine Updates wie bei Hibernate CascadeType.SAVE_UPDATE
.
In meinem Fall wurde es dadurch verursacht, dass ich nicht CascadeType
auf der @ManyToOne
Seite der bidirektionalen Beziehung stand. Genauer gesagt hatte ich CascadeType.ALL
auf der @OneToMany
Seite und hatte es nicht an @ManyToOne
. Hinzufügen CascadeType.ALL
zu@ManyToOne
um das Problem beheben.
Eins-zu-viele- Seite:
@OneToMany(cascade = CascadeType.ALL, mappedBy="globalConfig", orphanRemoval = true)
private Set<GlobalConfigScope>gcScopeSet;
Viele-zu-eins-Seite (verursachte das Problem)
@ManyToOne
@JoinColumn(name="global_config_id")
private GlobalConfig globalConfig;
Viele zu eins (durch Hinzufügen behoben CascadeType.PERSIST
)
@ManyToOne(cascade = CascadeType.PERSIST)
@JoinColumn(name="global_config_id")
private GlobalConfig globalConfig;
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 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 catch
Codeblock 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;
}
Nicht verwenden, Cascade.All
bis Sie wirklich müssen. Role
und Permission
haben bidirektionale manyToMany
Beziehung. Dann würde der folgende Code gut funktionieren
Permission p = new Permission();
p.setName("help");
Permission p2 = new Permission();
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 = new Role();
role.setAvailable(true);
role.setDescription("a test role");
role.setRole("admin");
List<Permission> pList = new ArrayList<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.
Wenn Ihre Sammlung nullbar ist, versuchen Sie einfach: object.SetYouColection(null);
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) .
Employee emp = new Employee();
emp.setDept(new Dept(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 deptId
PKID alsnull
von der aufrufenden Methode und ich den gleichen Fehler.
Achten Sie also auf null
Werte für die PK-ID
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. Ex
@Transactional
public someService() {
Entity someEntity = new Entity();
AssocaiatedEntity associatedEntity = new AssocaitedEntity();
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 merge
ein 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.
@OneToMany(cascade = {CascadeType.ALL})
@Column(name = "ListOfCarsDrivenByDriver")
private List<Car_OneToMany> listOfCarsBeingDriven = new ArrayList<Car_OneToMany>();
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.
Der Vollständigkeit halber: A.
org.hibernate.TransientPropertyValueException
mit Nachricht
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 .
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:
this.lastName = lastName;
this.isAdmin = isAdmin;
this.accountStatus = "Active";
this.setNewPassword(password);
this.timeJoin = new Date();
create();
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.
this.lastName = lastName;
this.isAdmin = isAdmin;
this.accountStatus = "Active";
this.timeJoin = new Date();
create();
this.setNewPassword(password);
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 fest B
und 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);
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.
@Entity(name = "ic_advance_salary")
@Table(name = "ic_advance_salary")
public class AdvanceSalary extends BaseDO{
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id")
private Integer id;
@ManyToOne(fetch = FetchType.EAGER)
@JoinColumn(name = "employee_id", nullable = false)
private Employee employee;
@Column(name = "employee_id", insertable=false, updatable=false)
@NotNull(message="Please enter employee Id")
private Long employee_id;
@Column(name = "advance_date")
@DateTimeFormat(pattern = "dd-MMM-yyyy")
@NotNull(message="Please enter advance date")
private Date advance_date;
@Column(name = "amount")
@NotNull(message="Please enter Paid Amount")
private Double amount;
@Column(name = "cheque_date")
@DateTimeFormat(pattern = "dd-MMM-yyyy")
private Date cheque_date;
@Column(name = "cheque_no")
private String cheque_no;
@Column(name = "remarks")
private String remarks;
public AdvanceSalary() {
}
public AdvanceSalary(Integer advance_salary_id) {
this.id = advance_salary_id;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public Employee getEmployee() {
return employee;
}
public void setEmployee(Employee employee) {
this.employee = employee;
}
public Long getEmployee_id() {
return employee_id;
}
public void setEmployee_id(Long employee_id) {
this.employee_id = employee_id;
}
}
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.
Fall 2:
Übergeordnete Klasse
public class Reference implements Serializable {
@Id
@Column(precision=20, scale=0)
private BigInteger id;
@Temporal(TemporalType.TIMESTAMP)
private Date modifiedOn;
@OneToOne(mappedBy="reference")
private ReferenceAdditionalDetails refAddDetails;
.
.
.
}
Kinderklasse:
public class ReferenceAdditionalDetails implements Serializable{
private static final long serialVersionUID = 1L;
@Id
@OneToOne
@JoinColumn(name="reference",referencedColumnName="id")
private Reference reference;
private String preferedSector1;
private String preferedSector2;
.
.
}
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)
.
.
reference.setRefAddDetails(null);
reference = referenceDao.create(reference);
entityManager.flush();
.
.
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:
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "feedbackSeq")
@Id
private Long id;
Ich muss den Wert zuweisen question.setId(1L);
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.