Saya pada dasarnya memiliki beberapa objek dalam konfigurasi ini (model data sebenarnya sedikit lebih kompleks):
- A memiliki hubungan banyak-ke-banyak dengan B. (B memiliki
inverse="true"
) - B memiliki hubungan banyak-ke-satu dengan C. (saya telah
cascade
menyetel ke"save-update"
) - C adalah sejenis tabel tipe / kategori.
Juga, saya mungkin harus menyebutkan bahwa kunci utama dihasilkan oleh database saat menyimpan.
Dengan data saya, saya terkadang mengalami masalah di mana A memiliki sekumpulan objek B yang berbeda, dan objek B ini merujuk ke objek C yang sama.
Ketika saya menelepon session.saveOrUpdate(myAObject)
, saya mendapatkan error hibernasi mengatakan: "a different object with the same identifier value was already associated with the session: C"
. Saya tahu bahwa hibernasi tidak dapat menyisipkan / memperbarui / menghapus objek yang sama dua kali dalam sesi yang sama, tetapi adakah cara untuk mengatasi ini? Ini sepertinya tidak akan menjadi situasi yang tidak biasa.
Selama penelitian saya tentang masalah ini, saya telah melihat orang-orang menyarankan penggunaan session.merge()
, tetapi ketika saya melakukan itu, setiap objek yang "bertentangan" dimasukkan ke dalam database sebagai objek kosong dengan semua nilai disetel ke nol. Jelas bukan itu yang kita inginkan.
[Sunting] Hal lain yang lupa saya sebutkan adalah (karena alasan arsitektur di luar kendali saya), setiap membaca atau menulis perlu dilakukan dalam sesi terpisah.
Jawaban:
Kemungkinan besar itu karena objek B tidak merujuk ke instance objek Java C yang sama. Mereka merujuk ke baris yang sama dalam database (yaitu kunci utama yang sama) tetapi salinannya berbeda.
Jadi yang terjadi adalah sesi Hibernate, yang mengelola entitas, akan melacak objek Java mana yang sesuai dengan baris dengan kunci utama yang sama.
Salah satu opsinya adalah memastikan bahwa Entitas objek B yang merujuk ke baris yang sama sebenarnya merujuk ke instance objek yang sama dari C. Alternatifnya, matikan cascading untuk variabel anggota tersebut. Dengan cara ini saat B bertahan, C tidak. Anda harus menyimpan C secara terpisah. Jika C adalah tabel tipe / kategori, maka mungkin masuk akal untuk seperti itu.
sumber
Cukup setel cascade ke MERGE, itu akan berhasil.
sumber
Anda hanya perlu melakukan satu hal. Jalankan
session_object.clear()
dan kemudian simpan objek baru tersebut. Ini akan menghapus sesi (sesuai namanya) dan menghapus objek duplikat yang menyinggung dari sesi Anda.sumber
Saya setuju dengan @Hemant Kumar, terima kasih banyak. Menurut solusinya, saya menyelesaikan masalah saya.
Sebagai contoh:
@Test public void testSavePerson() { try (Session session = sessionFactory.openSession()) { Transaction tx = session.beginTransaction(); Person person1 = new Person(); Person person2 = new Person(); person1.setName("222"); person2.setName("111"); session.save(person1); session.save(person2); tx.commit(); } }
Person.java
public class Person { private int id; private String name; @Id @Column(name = "id") public int getId() { return id; } public void setId(int id) { this.id = id; } @Basic @Column(name = "name") public String getName() { return name; } public void setName(String name) { this.name = name; } }
Kode ini selalu membuat kesalahan dalam aplikasi saya:,
A different object with the same identifier value was already associated with the session
kemudian saya menemukan bahwa saya lupa menaikkan kunci utama saya secara otomatis!Solusi saya adalah menambahkan kode ini pada kunci utama Anda:
@GeneratedValue(strategy = GenerationType.AUTO)
sumber
Ini berarti Anda mencoba menyimpan beberapa baris dalam tabel Anda dengan referensi ke objek yang sama.
periksa properti id Kelas Entitas Anda.
@Id private Integer id;
untuk
@Id @GeneratedValue(strategy = GenerationType.IDENTITY) @Column(unique = true, nullable = false) private Integer id;
sumber
Mentransfer tugas menetapkan ID objek dari Hibernate ke database dengan menggunakan:
<generator class="native"/>
Ini memecahkan masalah saya.
sumber
Tambahkan anotasi @GeneratedValue ke kacang yang Anda sisipkan.
sumber
Salah satu cara untuk mengatasi masalah di atas adalah dengan menimpa
hashcode()
.Juga bersihkan sesi hibernasi sebelum dan sesudah penyimpanan.
Menyetel objek yang terlepas secara eksplisit
null
juga membantu.sumber
Baru saja menemukan pesan ini tetapi dalam kode c #. Tidak yakin apakah itu relevan (meskipun pesan kesalahannya persis sama).
Saya sedang men-debug kode dengan breakpoint dan memperluas beberapa koleksi melalui anggota pribadi sementara debugger berada di titik putus. Setelah menjalankan kembali kode tanpa menggali melalui struktur membuat pesan kesalahan hilang. Sepertinya tindakan melihat ke dalam koleksi pribadi yang lambat dimuat telah membuat NHibernate memuat hal-hal yang seharusnya tidak dimuat pada saat itu (karena mereka adalah anggota pribadi).
Kode itu sendiri dibungkus dalam transaksi yang cukup rumit yang dapat memperbarui sejumlah besar catatan dan banyak ketergantungan sebagai bagian dari transaksi itu (proses impor).
Semoga menjadi petunjuk bagi siapa pun yang menemukan masalah ini.
sumber
Temukan atribut "Cascade" dalam Hibernate dan hapuslah. Ketika Anda menyetel "Cascade" tersedia, itu akan memanggil operasi lain (menyimpan, memperbarui dan menghapus) pada entitas lain yang memiliki hubungan dengan kelas terkait. Sehingga nilai identitas yang sama akan terjadi. Itu berhasil dengan saya.
sumber
Saya mengalami kesalahan ini beberapa hari yang lalu dan saya mempercepat terlalu banyak waktu untuk memperbaiki kesalahan ini.
public boolean save(OrderHeader header) { Session session = sessionFactory.openSession(); Transaction transaction = session.beginTransaction(); try { session.save(header); for (OrderDetail detail : header.getDetails()) { session.save(detail); } transaction.commit(); session.close(); return true; } catch (HibernateException exception) { exception.printStackTrace(); transaction.rollback(); return false; } }
Sebelum saya mendapatkan kesalahan ini, saya tidak menyebutkan tipe pembuatan ID pada Objek OrderDetil. ketika tanpa membuat id Orderdetails 'itu membuat Id sebagai 0 untuk setiap objek OrderDetail. ini yang dijelaskan #jbx. Ya itu jawaban terbaik. ini satu contoh bagaimana hal itu terjadi.
sumber
Coba tempatkan kode kueri Anda sebelumnya. Itu memperbaiki masalah saya. mis. ubah ini:
untuk ini:
sumber
Anda mungkin tidak menyetel pengenal objek sebelum memanggil kueri pembaruan.
sumber
Saya menemui masalah karena pembangkitan primary key salah, ketika saya menyisipkan baris seperti ini:
public void addTerminal(String typeOfDevice,Map<Byte,Integer> map) { // TODO Auto-generated method stub try { Set<Byte> keySet = map.keySet(); for (Byte byte1 : keySet) { Device device=new Device(); device.setNumDevice(DeviceCount.map.get(byte1)); device.setTimestamp(System.currentTimeMillis()); device.setTypeDevice(byte1); this.getHibernateTemplate().save(device); } System.out.println("hah"); }catch (Exception e) { // TODO: handle exception logger.warn("wrong"); logger.warn(e.getStackTrace()+e.getMessage()); } }
Saya mengubah kelas pembuat id menjadi identitas
<id name="id" type="int"> <column name="id" /> <generator class="identity" /> </id>
sumber
Dalam kasus saya hanya flush () tidak berhasil. Saya harus menggunakan clear () setelah flush ().
public Object merge(final Object detachedInstance) { this.getHibernateTemplate().flush(); this.getHibernateTemplate().clear(); try { this.getHibernateTemplate().evict(detachedInstance); } }
sumber
jika Anda menggunakan EntityRepository, gunakan saveAndFlush alih-alih simpan
sumber
Jika meninggalkan tab ekspresi di IDE saya terbuka yang membuat panggilan hibernasi pada objek menyebabkan pengecualian ini. Saya mencoba menghapus objek yang sama ini. Juga saya mengalami breakpoint pada panggilan hapus yang tampaknya diperlukan untuk membuat kesalahan ini terjadi. Cukup membuat tab ekspresi lain menjadi tab depan atau mengubah pengaturan ide agar tidak berhenti di breakpoint memecahkan masalah ini.
sumber
Pastikan, entitas Anda memiliki Jenis Generasi yang sama dengan semua Entitas yang Dipetakan
Mis: Peran Pengguna
public class UserRole extends AbstractDomain { @Id @GeneratedValue(strategy = GenerationType.AUTO) private Long id; private String longName; private String shortName; @Enumerated(EnumType.STRING) private CommonStatus status; private String roleCode; private Long level; @Column(columnDefinition = "integer default 0") private Integer subRoleCount; private String modification; @ManyToOne(fetch = FetchType.LAZY) private TypeOfUsers licenseType;
}
Modul:
public class Modules implements Serializable { @Id @GeneratedValue(strategy = GenerationType.AUTO) private Long id; private String longName; private String shortName;
}
Entitas Utama dengan Pemetaan
public class RoleModules implements Serializable{ @Id @GeneratedValue(strategy = GenerationType.AUTO) private Long id; @ManyToOne(fetch = FetchType.LAZY, cascade = CascadeType.MERGE) private UserRole role; @ManyToOne(fetch = FetchType.LAZY, cascade = CascadeType.MERGE) private Modules modules; @Type(type = "yes_no") private boolean isPrimaryModule; public boolean getIsPrimaryModule() { return isPrimaryModule; }
}
sumber
Selain semua jawaban sebelumnya, kemungkinan perbaikan untuk masalah ini dalam proyek skala besar, jika Anda menggunakan Objek Nilai untuk kelas Anda tidak menyetel atribut id di kelas Transformer VO.
sumber
cukup lakukan transaksi saat ini.
sekarang Anda dapat memulai Transaksi lain dan melakukan apa pun di entitas
sumber
Kasus lain ketika pesan kesalahan yang sama dapat dihasilkan, kustom
allocationSize
:@Id @Column(name = "idpar") @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "paramsSequence") @SequenceGenerator(name = "paramsSequence", sequenceName = "par_idpar_seq", allocationSize = 20) private Long id;
tanpa pencocokan
alter sequence par_idpar_seq increment 20;
dapat menyebabkan validasi batasan selama penyisipan (yang mudah dipahami) atau "objek berbeda dengan nilai pengenal yang sama telah dikaitkan dengan sesi" - kasus ini kurang jelas.
sumber