Saya menerima kesalahan berikut ketika saya menyimpan objek menggunakan Hibernate
object references an unsaved transient instance - save the transient instance before flushing
Saya menerima kesalahan berikut ketika saya menyimpan objek menggunakan Hibernate
object references an unsaved transient instance - save the transient instance before flushing
Jawaban:
Anda harus memasukkan cascade="all"
(jika menggunakan xml) atau cascade=CascadeType.ALL
(jika menggunakan anotasi) pada pemetaan koleksi Anda.
Ini terjadi karena Anda memiliki koleksi di entitas Anda, dan koleksi itu memiliki satu atau lebih item yang tidak ada dalam database. Dengan menentukan opsi di atas, Anda memberi tahu hibernate untuk menyimpannya ke basis data saat menyimpan induknya.
Saya percaya ini mungkin hanya jawaban berulang, tetapi hanya untuk memperjelas, saya mendapatkan ini pada @OneToOne
pemetaan dan juga @OneToMany
. Dalam kedua kasus, itu adalah fakta bahwa Child
objek yang saya tambahkan ke Parent
belum disimpan dalam database. Jadi ketika saya menambahkan Child
ke Parent
, lalu menyimpan Parent
, Hibernate akan melemparkan "object references an unsaved transient instance - save the transient instance before flushing"
pesan saat menyimpan Induk.
Menambahkan di cascade = {CascadeType.ALL}
atas Parent's
mengacu pada Child
memecahkan masalah dalam kedua kasus. Ini menyelamatkan Child
dan Parent
.
Maaf atas jawaban berulang, hanya ingin menjelaskan lebih lanjut untuk orang-orang.
@OneToOne(cascade = {CascadeType.ALL})
@JoinColumn(name = "performancelog_id")
public PerformanceLog getPerformanceLog() {
return performanceLog;
}
new MyEntity
(tanpa menyinkronkannya ke database - pembilasan), alih-alih mendapatkan instance yang disinkronkan dari database. Membuat pertanyaan Hibernate menggunakan instance itu memberi tahu Anda bahwa apa yang Anda harapkan berada dalam database berbeda dari apa yang Anda miliki dalam memori aplikasi Anda. Dalam hal ini - cukup menyinkronkan / mendapatkan instabnce entitas Anda dari DB dan menggunakannya. Tidak perlu CascadeType.ALL.
Ini terjadi saat menyimpan objek ketika Hibernate merasa perlu menyimpan objek yang dikaitkan dengan objek yang Anda simpan.
Saya punya masalah ini dan tidak ingin menyimpan perubahan ke objek yang direferensikan jadi saya ingin jenis kaskade menjadi NONE.
Caranya adalah memastikan bahwa ID dan VERSION dalam objek yang direferensikan diatur sehingga Hibernate tidak berpikir bahwa objek yang direferensikan adalah objek baru yang perlu disimpan. Ini berhasil untuk saya.
Lihat semua hubungan dalam kelas yang Anda simpan untuk mengetahui objek terkait (dan objek terkait dari objek terkait) dan memastikan bahwa ID dan VERSI diatur di semua objek dari pohon objek.
Seperti yang saya jelaskan dalam artikel ini saat menggunakan JPA dan Hibernate, sebuah entitas dapat berada di salah satu dari 4 negara berikut:
Baru - Objek yang baru dibuat yang belum pernah dikaitkan dengan Hibernate Session (alias Persistence Context) dan tidak dipetakan ke baris tabel basis data apa pun yang dianggap berada dalam keadaan Baru atau Transien.
Untuk bertahan, kita perlu secara eksplisit memanggil persist
metode atau memanfaatkan mekanisme kegigihan transitif.
Persistent - Entitas persisten telah dikaitkan dengan baris tabel database dan dikelola oleh Konteks Persistence yang sedang berjalan.
Setiap perubahan yang dibuat untuk entitas seperti itu akan dideteksi dan disebarkan ke database (selama Sesi flush-time).
Terpisah - Setelah Persistence Konteks yang sedang berjalan ditutup, semua entitas yang sebelumnya dikelola menjadi terpisah. Perubahan yang berurutan tidak akan lagi dilacak dan tidak ada sinkronisasi basis data otomatis yang akan terjadi.
Dihapus - Meskipun JPA menuntut agar entitas yang dikelola hanya diizinkan untuk dihapus, Hibernate juga dapat menghapus entitas yang terpisah (tetapi hanya melalui remove
pemanggilan metode).
Untuk memindahkan entitas dari satu status ke kondisi lainnya, Anda dapat menggunakan persist
, remove
atau merge
metode.
Masalah yang Anda uraikan dalam pertanyaan Anda:
object references an unsaved transient instance - save the transient instance before flushing
disebabkan oleh mengaitkan entitas di negara bagian Baru ke entitas yang ada di negara bagian yang Dikelola .
Ini bisa terjadi ketika Anda mengasosiasikan entitas anak ke koleksi satu-ke-banyak di entitas induk, dan koleksi tersebut tidak cascade
transisi status entitas entitas.
Jadi, seperti yang saya jelaskan di artikel ini , Anda bisa memperbaikinya dengan menambahkan kaskade ke asosiasi entitas yang memicu kegagalan ini, sebagai berikut:
@OneToOne
asosiasi@OneToOne(
mappedBy = "post",
orphanRemoval = true,
cascade = CascadeType.ALL)
private PostDetails details;
Perhatikan
CascadeType.ALL
nilai yang kami tambahkan untukcascade
atribut.
@OneToMany
asosiasi@OneToMany(
mappedBy = "post",
orphanRemoval = true,
cascade = CascadeType.ALL)
private List<Comment> comments = new ArrayList<>();
Sekali lagi, CascadeType.ALL
ini cocok untuk asosiasi dua arah@OneToMany
.
Sekarang, agar kaskade berfungsi dengan baik dalam dua arah, Anda juga perlu memastikan bahwa asosiasi orang tua dan anak dalam sinkronisasi.
Lihat artikel ini untuk detail lebih lanjut tentang apa cara terbaik untuk mencapai tujuan ini.
@ManyToMany
asosiasi@ManyToMany(
mappedBy = "authors",
cascade = {
CascadeType.PERSIST,
CascadeType.MERGE
}
)
private List<Book> books = new ArrayList<>();
Dalam sebuah @ManyToMany
asosiasi, Anda tidak dapat menggunakan CascadeType.ALL
atau orphanRemoval
karena ini akan menyebarkan transisi status entitas hapus dari satu induk ke entitas induk lainnya.
Oleh karena itu, untuk @ManyToMany
asosiasi, Anda biasanya melakukan kaskade CascadeType.PERSIST
atau CascadeType.MERGE
operasi. Atau, Anda dapat memperluas itu ke DETACH
atau REFRESH
.
Untuk detail lebih lanjut tentang cara terbaik untuk memetakan
@ManyToMany
asosiasi, lihat artikel ini juga.
Atau, jika Anda ingin menggunakan "kekuatan" minimal (mis. Jika Anda tidak ingin penghapusan kaskade) untuk mencapai apa yang Anda inginkan, gunakan
import org.hibernate.annotations.Cascade;
import org.hibernate.annotations.CascadeType;
...
@Cascade({CascadeType.SAVE_UPDATE})
private Set<Child> children;
@ManyToMany(cascade={PERSIST, MERGE, REFRESH, DETACH})
(semua kecuali HAPUS) tidak membuat pembaruan seperti yang dilakukan Hibernate CascadeType.SAVE_UPDATE
.
Dalam kasus saya itu disebabkan oleh tidak memiliki CascadeType
di @ManyToOne
sisi hubungan dua arah. Untuk lebih tepat, aku punya CascadeType.ALL
di @OneToMany
sisi dan tidak memiliki itu @ManyToOne
. Menambahkan CascadeType.ALL
untuk @ManyToOne
menyelesaikan masalah.
Satu-ke-banyak sisi:
@OneToMany(cascade = CascadeType.ALL, mappedBy="globalConfig", orphanRemoval = true)
private Set<GlobalConfigScope>gcScopeSet;
Banyak-ke-satu sisi (menyebabkan masalah)
@ManyToOne
@JoinColumn(name="global_config_id")
private GlobalConfig globalConfig;
Banyak-ke-satu (diperbaiki dengan menambahkan CascadeType.PERSIST
)
@ManyToOne(cascade = CascadeType.PERSIST)
@JoinColumn(name="global_config_id")
private GlobalConfig globalConfig;
Ini terjadi bagi saya ketika mempertahankan entitas di mana catatan yang ada di database memiliki nilai NULL untuk bidang yang dianotasi dengan @Version (untuk penguncian optimis). Memperbarui nilai NULL ke 0 dalam basis data mengoreksi ini.
Ini bukan satu-satunya alasan untuk kesalahan ini. Saya baru saja menemukannya untuk kesalahan ketik dalam pengkodean saya, yang saya percaya, menetapkan nilai entitas yang sudah disimpan.
X x2 = new X();
x.setXid(memberid); // Error happened here - x was a previous global entity I created earlier
Y.setX(x2);
Saya melihat kesalahan dengan menemukan variabel mana yang menyebabkan kesalahan (dalam hal ini String xid
). Saya menggunakan catch
sekitar seluruh blok kode yang menyelamatkan entitas dan mencetak jejak.
{
code block that performed the operation
} catch (Exception e) {
e.printStackTrace(); // put a break-point here and inspect the 'e'
return ERROR;
}
Jangan gunakan Cascade.All
sampai Anda benar-benar harus melakukannya. Role
dan Permission
memiliki manyToMany
hubungan dua arah . Kemudian kode berikut akan berfungsi dengan baik
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);
sementara jika objek hanya "baru", maka itu akan melempar kesalahan yang sama.
Jika koleksi Anda tidak dapat dibatalkan, cobalah: object.SetYouColection(null);
Untuk menambahkan 2 sen, saya mendapatkan masalah yang sama ketika saya secara tidak sengaja mengirim null
sebagai ID. Kode di bawah ini menggambarkan skenario saya (dan OP tidak menyebutkan skenario spesifik) .
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);
Di sini saya mengatur id departemen yang ada ke instance karyawan baru tanpa benar-benar mendapatkan entitas departemen terlebih dahulu, karena saya tidak ingin memunculkan kueri pemilihan lain.
Dalam beberapa skenario, deptId
PKID berasal null
dari metode panggilan dan saya mendapatkan kesalahan yang sama.
Jadi, perhatikan null
nilai untuk PK ID
Masalah ini terjadi pada saya ketika saya membuat entitas baru dan entitas terkait dalam metode yang ditandai sebagai @Transactional
, lalu melakukan kueri sebelum menyimpan. 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);
}
Untuk memperbaikinya, saya melakukan kueri sebelum membuat entitas baru.
di samping semua jawaban baik lainnya, ini bisa terjadi jika Anda menggunakan merge
untuk bertahan suatu objek dan secara tidak sengaja lupa untuk menggunakan referensi objek yang digabung dalam kelas induk. pertimbangkan contoh berikut
merge(A);
B.setA(A);
persist(B);
Dalam kasus ini, Anda menggabungkan A
tetapi lupa untuk menggunakan objek gabungan A
. untuk menyelesaikan masalah Anda harus menulis ulang kode seperti ini.
A=merge(A);//difference is here
B.setA(A);
persist(B);
Saya juga menghadapi situasi yang sama. Dengan mengatur anotasi berikut di atas properti membuatnya menyelesaikan pengecualian yang diminta.
Pengecualian yang saya hadapi.
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
Untuk mengatasinya, anotasi yang saya gunakan.
@OneToMany(cascade = {CascadeType.ALL})
@Column(name = "ListOfCarsDrivenByDriver")
private List<Car_OneToMany> listOfCarsBeingDriven = new ArrayList<Car_OneToMany>();
Apa yang membuat Hibernate melempar pengecualian:
Pengecualian ini dilemparkan ke konsol Anda karena objek anak yang saya lampirkan ke objek induk tidak ada dalam database pada saat itu.
Dengan menyediakan @OneToMany(cascade = {CascadeType.ALL})
, ini memberitahu Hibernate untuk menyimpannya ke database sambil menyimpan objek induk.
Demi kelengkapan: A
org.hibernate.TransientPropertyValueException
dengan pesan
object references an unsaved transient instance - save the transient instance before flushing
juga akan terjadi ketika Anda mencoba untuk bertahan / menggabungkan suatu entitas dengan referensi ke entitas lain yang kebetulan terlepas .
Satu alasan lain yang mungkin: dalam kasus saya, saya berusaha menyelamatkan anak sebelum menyelamatkan orang tua, pada entitas baru.
Kode itu seperti ini dalam model User.java:
this.lastName = lastName;
this.isAdmin = isAdmin;
this.accountStatus = "Active";
this.setNewPassword(password);
this.timeJoin = new Date();
create();
Metode setNewPassword () membuat catatan PasswordHistory dan menambahkannya ke koleksi sejarah di Pengguna. Karena pernyataan create () belum dieksekusi untuk induk, itu mencoba menyimpan ke koleksi entitas yang belum dibuat. Yang harus saya lakukan untuk memperbaikinya adalah memindahkan panggilan setNewPassword () setelah panggilan untuk membuat ().
this.lastName = lastName;
this.isAdmin = isAdmin;
this.accountStatus = "Active";
this.timeJoin = new Date();
create();
this.setNewPassword(password);
Ada kemungkinan lain yang dapat menyebabkan kesalahan ini dalam hibernasi. Anda dapat menetapkan referensi yang belum disimpan dari objek Anda A
ke entitas terlampir B
dan ingin tetap objek C
. Bahkan dalam kasus ini, Anda akan mendapatkan kesalahan yang disebutkan di atas.
Saya pikir itu karena Anda telah mencoba untuk bertahan objek yang memiliki referensi ke objek lain yang belum bertahan, dan itu mencoba di "sisi DB" untuk menempatkan referensi ke baris yang tidak ada
Cara sederhana untuk memecahkan masalah ini adalah menyelamatkan kedua entitas. pertama simpan entitas anak dan kemudian simpan entitas induk. Karena entitas induk bergantung pada entitas anak untuk nilai kunci asing.
Di bawah ini ujian sederhana hubungan satu lawan satu
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);
Salah satu kemungkinan penyebab kesalahan adalah tidak adanya pengaturan nilai entitas induk; misalnya untuk hubungan departemen-karyawan Anda harus menulis ini untuk memperbaiki kesalahan:
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);
Ada begitu banyak kemungkinan kesalahan ini, beberapa kemungkinan lain juga ada di halaman tambah atau edit. Dalam kasus saya, saya mencoba untuk menyimpan objek AdvanceSalary. Masalahnya adalah bahwa dalam pengeditan AdvanceSalary employee.employee_id adalah null Karena pada pengeditan saya tidak menetapkan employee.employee_id. Saya telah membuat bidang tersembunyi dan mengaturnya. kode saya bekerja dengan sangat baik.
@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;
}
}
Saya menghadapi pengecualian ini ketika saya tidak bertahan pada objek orang tua tetapi saya menyelamatkan anak itu. Untuk mengatasi masalah ini, dengan di sesi yang sama saya bertahan objek anak dan orang tua dan menggunakan CascadeType.ALL pada orang tua.
Kasus 1: Saya mendapatkan pengecualian ini ketika saya mencoba membuat orangtua dan menyimpan referensi orangtua itu untuk anaknya dan kemudian beberapa DELETE / UPDATE query (JPQL) lainnya. Jadi saya hanya flush () entitas yang baru dibuat setelah membuat induk dan setelah membuat anak menggunakan referensi induk yang sama. Ini berhasil untuk saya.
Kasus 2:
Kelas induk
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;
.
.
.
}
Kelas Anak:
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;
.
.
}
Dalam kasus di atas di mana induk (Referensi) dan anak (ReferenceAdditionalDetails) memiliki hubungan OneToOne dan ketika Anda mencoba membuat entitas Referensi dan kemudian anaknya (ReferenceAdditionalDetails), itu akan memberi Anda pengecualian yang sama. Jadi untuk menghindari pengecualian Anda harus menetapkan nol untuk kelas anak dan kemudian membuat induknya. (Contoh Kode)
.
.
reference.setRefAddDetails(null);
reference = referenceDao.create(reference);
entityManager.flush();
.
.
Masalah saya terkait dengan @BeforeEach
JUnit. Dan bahkan jika saya menyimpan entitas terkait (dalam kasus saya @ManyToOne
), saya mendapatkan kesalahan yang sama.
Masalahnya entah bagaimana terkait dengan urutan yang saya miliki di orang tua saya. Jika saya menetapkan nilai ke atribut itu, masalahnya terpecahkan.
Ex. Jika saya memiliki Pertanyaan entitas yang dapat memiliki beberapa kategori (satu atau lebih) dan Pertanyaan entitas memiliki urutan:
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "feedbackSeq")
@Id
private Long id;
Saya harus menetapkan nilainya question.setId(1L);
Buat Constructor pemetaan Anda di kelas dasar Anda. Seperti jika Anda ingin hubungan One-To-One di Entity A, Entity B. jika Anda mengambil A sebagai kelas dasar, maka A harus memiliki Konstruktor memiliki B sebagai argumen.