JPA / EJB koduyla "ayrılan varlık kalıcı hataya geçti"


81

Bu temel JPA / EJB kodunu çalıştırmaya çalışıyorum:

public static void main(String[] args){
         UserBean user = new UserBean();
         user.setId(1);
         user.setUserName("name1");
         user.setPassword("passwd1");
         em.persist(user);
  }

Bu hatayı alıyorum:

javax.ejb.EJBException: javax.persistence.PersistenceException: org.hibernate.PersistentObjectException: detached entity passed to persist: com.JPA.Database

Herhangi bir fikir?

İnternette araştırıyorum ve bulmamın nedeni şuydu:

Bunun nedeni, nesneleri nasıl oluşturduğunuzdan kaynaklanıyordu, örn. ID özelliğini açıkça ayarladıysanız. Kimlik atamasının kaldırılması sorunu çözdü.

Ama anlamadım, kodun çalışması için neyi değiştirmem gerekecek?

Yanıtlar:


50

ERD

Diyelim ki iki varlığınız var Albumve Photo. Albüm pek çok fotoğraf içeriyor, bu yüzden bire çok ilişki var.

Albüm sınıfı

@Entity
public class Album {
    @Id
    @GeneratedValue(strategy=GenerationType.AUTO)
    Integer albumId;

    String albumName;

    @OneToMany(targetEntity=Photo.class,mappedBy="album",cascade={CascadeType.ALL},orphanRemoval=true)
    Set<Photo> photos = new HashSet<Photo>();
}

Fotoğraf sınıfı

@Entity
public class Photo{
    @Id
    @GeneratedValue(strategy=GenerationType.AUTO)
    Integer photo_id;

    String photoName;

    @ManyToOne(targetEntity=Album.class)
    @JoinColumn(name="album_id")
    Album album;

}

Kalıcı veya birleştirmeden önce yapmanız gereken şey, her fotoğrafta Albüm referansını ayarlamaktır.

        Album myAlbum = new Album();
        Photo photo1 = new Photo();
        Photo photo2 = new Photo();

        photo1.setAlbum(myAlbum);
        photo2.setAlbum(myAlbum);       

Devam etmeden veya birleşmeden önce ilgili varlığın nasıl ekleneceği budur.


2
Jenerik kullanıyorsanız, "targetEntity = Photo.class" kullanmaya gerek yoktur
Rollerball

merhaba, albüm nesnesini photo1 nad photo2 olarak ayarladıktan sonra ... Fotoğraflar veya Albüm listesini kaydetmek için hangi nesneye sahibiz?
Dilanka Rathnayake

130

Hata, nesnenin kimliği ayarlandığı için oluşur. Hazırda bekletme, geçici ve ayrılmış nesneler arasında ayrım yapar ve persistyalnızca geçici nesnelerle çalışır. Eğer persist(bu kimlik ayarlanır çünkü hangi) nesnesi müstakil olduğu sonucuna, bu hatayı "müstakil nesne devam geçirilen" dönecektir. Daha fazla ayrıntıyı burada ve burada bulabilirsiniz .

Ancak bu yalnızca geçerlidir eğer otomatik oluşturulan olmasını birincil anahtar belirttiniz: alanı her zaman sonra, elle kod eserler ayarlanması yapılandırılmışsa.


Hazırda bekletme değil JPA kullanıyorum dediğimde teknik olarak haklı olacak mıyım, bu yüzden yukarıdaki ifade doğru olmamalı mı?
JPA'da acemiyim

Sun'ın JPA Javadoc'u ( java.sun.com/javaee/5/docs/api/javax/persistence/… ) ve Toplink'inki tamamen aynı ve teknik olarak doğru olduğunuzu gösteriyor. Ancak, bu, belirtimde ısrar () 'ın nasıl davranması gerektiğini söylediği şeye gerçekten bağlı ve ne yazık ki, bunun ne olduğunu bilmiyorum.
Tomislav Nakic-Alfirevic

Bu çözüm benim için çalıştı. Kimliği bir yerde saklayarak bir nesneye ısrar ediyordum. Daha sonra mevcut nesnenin üzerine yeni bir değer yazmak istiyorum, bu yüzden nesneyi yarattım, kimliği tekrar kopyaladım ve kaydetmeye çalıştığımda patladı. Sonunda, DB'yi yeniden sorgulamak (findById), değişiklikleri yapmak ve sonra o nesneyi sürdürmek zorunda kaldım .
cs94njw

24

Kaldırmak

user.setId(1);

çünkü DB'de otomatik olarak üretilir ve kalıcı komutla devam eder.


12

Cevabı aldım, kullanıyordum:

em.persist(user);

Israr yerine birleştirme kullandım:

em.merge(user);

Ama ısrarın neden işe yaramadığı hakkında hiçbir fikrim yok. :(


11
çözüm bu değil!
Ammar Bozorgvar

1
Biliyorum ama bu benim için çalıştı. burada sizin için çalışan başka bir cevap var mı? eğer evet ise, onu seçmekten çok mutlu olacağım.
zengr

4
Nesneniz hazırda bekletme oturumundan ayrılmış olduğundan veya nesne geçici olduğundan ancak hazırda bekletme, birincil anahtarı beyan ettiğiniz için onu ayrılmış olarak görür, Birleştirme kullanarak nesneyi oturuma tekrar eklersiniz, bu, veritabanınızdaki nesneleri güncellemenizi sağlar ; bkz: docs.jboss.org/hibernate/core/3.3/reference/en/html/…
Ben

11

oluşturmak için kullanırsanız id = GenerationType.AUTOStratejiyi varlığınızda .

Yerini user.setId (1)tarafından user.setId (null)ve sorun çözüldü.


5

Bunun çok geç olduğunu ve herkesin cevabı aldığını biliyorum. Ancak buna eklenecek biraz daha fazla: GenerateType ayarlandığında, bir nesnede persist () 'nin oluşturulan bir kimliği alması beklenir.

Kullanıcı tarafından zaten Kimlik olarak ayarlanmış bir değer varsa, hazırda bekletme bunu kaydedilmiş kayıt olarak değerlendirir ve bu nedenle ayrılmış olarak değerlendirilir.

kimlik boş ise - bu durumda tür AUTO veya IDENTITY vb. olduğunda, kimlik bir tablodan veya bir diziden oluşturulmadığı sürece boş bir işaretçi istisnası ortaya çıkar.

tasarım: bu, tablonun birincil anahtar olarak bir bean özelliğine sahip olması durumunda gerçekleşir. GenerateType yalnızca bir kimlik otomatik olarak oluşturulduğunda ayarlanmalıdır. bunu kaldırın ve ek, kullanıcı tarafından belirtilen kimlik ile çalışmalıdır. (birincil anahtar alanına eşlenmiş bir özelliğe sahip olmak kötü bir tasarımdır)


5

Burada .persist () yalnızca kaydı ekleyecektir. .Merge () kullanırsak , geçerli kimliğe sahip herhangi bir kayıt olup olmadığını kontrol edecek, varsa güncelleyecektir, aksi takdirde yeni bir kayıt ekleyecektir.


Cevabını alana kadar bana bir sürü zamana mal oldu. Çok teşekkür ederim!
Thach Van

3

Veritabanınızdaki kimliği birincil anahtar ve otomatik artış olarak ayarlarsanız, bu kod satırı yanlıştır:

user.setId(1);

Şununla dene:

public static void main(String[] args){
         UserBean user = new UserBean();
         user.setUserName("name1");
         user.setPassword("passwd1");
         em.persist(user);
  }

Bunu denedim ve bu hatayı aldığımı biliyorum:detached entity passed to persist
s1ddok

2

Bu sorunu yaşadım ve ikinci seviye önbellekten kaynaklanıyordu:

  1. Hazırda bekletme kullanan bir varlığı ısrarla
  2. Sonra, ikinci seviye önbellekle etkileşime girmeyen ayrı bir işlemden oluşturulan satırı sildim.
  3. Aynı tanımlayıcıya sahip başka bir varlığı ısrar ettim (tanımlayıcı değerlerim otomatik olarak oluşturulmuyor)

Bu nedenle, önbellek geçersiz olmadığından, hazırda bekletme, aynı varlığın ayrılmış bir örneğiyle uğraştığını varsaydı.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.