JPA OneToMany birçok çocuğu silmiyor


158

@OneToManyBir üst öğe ile alt öğe arasındaki basit bir eşlemeyle ilgili sorunum var . Her şey iyi çalışıyor, koleksiyondan kaldırdığımda yalnızca alt kayıtlar silinmiyor.

Ebeveyn:

@Entity
public class Parent {
    @Id
    @Column(name = "ID")
    private Long id;

    @OneToMany(cascade = {CascadeType.ALL}, mappedBy = "parent")
    private Set<Child> childs = new HashSet<Child>();

 ...
}

Çocuk:

@Entity
public class Child {
    @Id
    @Column(name = "ID")
    private Long id;

    @ManyToOne(cascade = CascadeType.ALL)
    @JoinColumn(name="PARENTID", nullable = false)
    private Parent parent;

  ...
}

Şimdi childs setinden ve alt öğeyi silersem, veritabanından silinmez. child.parentReferansı iptal etmeyi denedim , ama bu da işe yaramadı.

Varlıklar bir web uygulamasında kullanılır, silme işlemi Ajax isteğinin bir parçası olarak gerçekleşir. Kaydet düğmesine basıldığında silinmiş alt öğe listem yok, bu yüzden onları dolaylı olarak silemiyorum.

Yanıtlar:


253

JPA'nın davranışı doğrudur ( spesifikasyona göre anlamlıdır): nesneler yalnızca OneToMany koleksiyonundan kaldırdığınız için silinmez. Bunu yapan satıcıya özgü uzantılar var, ancak yerel JPA buna uygun değil.

Kısmen bunun nedeni, JPA'nın koleksiyondan kaldırılan bir şeyi silmesi gerekip gerekmediğini gerçekten bilmemesidir. Nesne modelleme terimleriyle bu, kompozisyon ve "toplama * arasındaki farktır .

In kompozisyon , alt varlık ebeveyn olmadan hiçbir varlığa sahiptir. Klasik bir örnek House ve Room arasındadır. Evi silin ve Odalar çok gidin.

Toplama daha gevşek bir dernektir ve Kurs ve Öğrenci tarafından belirlenir. Kursu Sil ve Öğrenci hala var (muhtemelen diğer Kurslarda).

Bu nedenle, bu davranışı (varsa) zorlamak için satıcıya özgü uzantılar kullanmanız veya alt öğeyi açıkça silmeniz VE ebeveynin koleksiyonundan kaldırmanız gerekir.

Farkındayım:


teşekkürler güzel açıklama. bu yüzden korktuğum gibi. (Ben sadece kurtarmak istedim önce ben bazı arama / okuma yaptım). nasılsa doğrudan JPA API ve nit Hibernate kullanmaya karar pişmanlık başlar .. Ben Chandra Patni işaretçisini deneyecek ve hazırda bekleme delete_orphan kaskad türü kullanacağım.
bert

Bu konuda benzer bir sorum var. Lütfen bu yazıya bir göz atın lütfen? stackoverflow.com/questions/4569857/…
Thang Pham

78
JPA 2.0 ile artık orphanRemoval = true seçeneğini kullanabilirsiniz
itsadok

2
Büyük ilk açıklama ve yetimRemoval hakkında iyi tavsiyeler. JPA'nın bu kaldırma türünü hesaba katmadığı hakkında hiçbir fikri yoktu. Hazırda Bekletme hakkında bildiklerim ile JPA'nın gerçekte ne yaptığı arasındaki nüanslar sinir bozucu olabilir.
sma

Kompozisyon ve Anlaşma arasındaki farkları ortaya çıkararak güzelce açıkladı!
Felipe Leão

73

Cletus'un cevabına ek olarak , Aralık 2010'dan bu yana finalde olan JPA 2.0 , ek açıklamalara bir orphanRemovalözellik getiriyor @OneToMany. Daha fazla ayrıntı için bu blog girişine bakın .

Spesifikasyon nispeten yeni olduğu için, tüm JPA 1 sağlayıcılarının son bir JPA 2 uygulaması olmadığını unutmayın. Örneğin, Hazırda Beklet 3.5.0-Beta-2 sürümü bu özelliği henüz desteklememektedir.


blog girişi - bağlantı koptu.
Steffi


43

Bunu deneyebilirsiniz:

@OneToOne(orphanRemoval=true) or @OneToMany(orphanRemoval=true).


2
Teşekkürler. Ancak soru JPA'dan 1 kez geri döndü. Ve bu seçenek daha önce mevcut değildi.
bert

9
Yine de bilmek iyi, JPA2 kez bunun için bir çözüm arayanlar için :)
alex440 15:15

20

Açıklandığı gibi, JPA ile ne istediğimi yapmak mümkün değil, bu yüzden hibernate.cascade ek açıklamasını kullandım, bununla birlikte, Ana sınıftaki ilgili kod şimdi şöyle görünüyor:

@OneToMany(cascade = {CascadeType.PERSIST, CascadeType.MERGE, CascadeType.REFRESH}, mappedBy = "parent")
@Cascade({org.hibernate.annotations.CascadeType.SAVE_UPDATE,
            org.hibernate.annotations.CascadeType.DELETE,
            org.hibernate.annotations.CascadeType.MERGE,
            org.hibernate.annotations.CascadeType.PERSIST,
            org.hibernate.annotations.CascadeType.DELETE_ORPHAN})
private Set<Child> childs = new HashSet<Child>();

Bu ebeveyn de silmiş olurdu gibi 'ALL' basit kullanımı olamazdı.



4

Bunu deneyebilirsiniz:

@OneToOne(cascade = CascadeType.REFRESH) 

veya

@OneToMany(cascade = CascadeType.REFRESH)

3
@Entity 
class Employee {
     @OneToOne(orphanRemoval=true)
     private Address address;
}

Buraya bakın .

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.