Apa perbedaan antara CascadeType.REMOVE dan orphanRemoval di JPA?

103

Apa perbedaannya

@OneToMany(cascade=REMOVE, mappedBy="customer")
public List<Order> getOrders() { ... }

dan

@OneToMany(mappedBy="customer", orphanRemoval="true")
public List<Order> getOrders() { ... }

Contoh ini dari Tutorial Java EE, tapi saya masih belum mengerti detailnya.

rand0m86
sumber
Penghapusan orphan berarti bahwa entitas dependen dihapus ketika hubungan dengan entitas "induk" mereka dihancurkan.
Rahul Tripathi
1
Menulis kasus uji yang mungkin menggambarkan konsep tersebut.
Martin Andersson

Jawaban:

153

Dari sini : -

Penghapusan Bertingkat

Menandai bidang referensi dengan CascadeType.REMOVE (atau CascadeType.ALL, yang menyertakan REMOVE) menunjukkan bahwa operasi penghapusan harus diturunkan secara otomatis ke objek entitas yang direferensikan oleh bidang itu (beberapa objek entitas dapat direferensikan oleh bidang koleksi):

@Entity
class Employee {
     :
    @OneToOne(cascade=CascadeType.REMOVE)
    private Address address;
     :
}

Penghapusan Anak Yatim

JPA 2 mendukung mode cascading hapus tambahan dan lebih agresif yang dapat ditentukan menggunakan elemen orphanRemoval dari anotasi @OneToOne dan @OneToMany:

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

PERBEDAAN:-

Perbedaan antara kedua pengaturan ini adalah dalam menanggapi pemutusan hubungan. Misalnya, seperti saat menyetel bidang alamat ke nol atau ke objek Alamat lain.

  • Jika orphanRemoval = true ditentukan, instance Alamat terputus secara otomatis dihapus. Ini berguna untuk membersihkan objek yang bergantung (misalnya Alamat) yang seharusnya tidak ada tanpa referensi dari objek pemilik (misalnya Karyawan).
  • Jika hanya cascade = CascadeType.REMOVE ditentukan tidak ada tindakan otomatis yang diambil karena memutuskan hubungan bukanlah
    operasi penghapusan .
Rahul Tripathi
sumber
87

Cara mudah untuk memahami perbedaan antara CascadeType.REMOVEdanorphanRemoval=true .

Untuk penghapusan yatim piatu: Jika Anda memanggil setOrders(null), Orderentitas terkait akan dihapus dalam db secara otomatis.

Untuk menghapus kaskade: Jika Anda memanggil setOrders(null), Orderentitas terkait TIDAK akan dihapus dalam db secara otomatis.

belajar
sumber
2
hapus === hapus
Abdull
10

Misalkan kita memiliki entitas anak dan entitas induk. Seorang orang tua dapat memiliki beberapa anak.

@Entity
class parent {
  //id and other fields
 @OneToMany (orphanRemoval = "true",cascade = CascadeType.REMOVE)
   Set<Person> myChildern;
}

OrphanRemoval adalah konsep ORM, yang memberi tahu jika anak itu yatim piatu. itu juga harus dihapus dari database.

Seorang anak menjadi yatim piatu jika tidak dapat diakses dari induknya. Misalnya, jika kita menghapus set objek Person (menyetelnya ke set kosong) atau menggantinya dengan set baru maka orang tua tidak bisa lagi mengakses anak-anak di set lama dan anak-anak menjadi yatim piatu sehingga anak-anak ditakdirkan untuk menjadi dihapus dalam database juga.

CascadeType.REMOVE adalah konsep tingkat database dan memberitahu jika induk dihapus, semua catatan terkait di tabel anak harus dihapus.

Tuan Q
sumber
2

Secara praktis perbedaannya terletak pada apakah Anda mencoba memperbarui data (PATCH) atau mengganti data sepenuhnya (PUT)

Katakanlah Anda menghapus customerthan menggunakan cascade=REMOVEjuga akan menghapus pesanan pelanggan yang tampaknya dimaksudkan dan berguna.

@OneToMany(cascade=REMOVE, mappedBy="customer")
public List<Order> getOrders() { ... }

Sekarang katakanlah Anda memperbarui a customerdengan orphanRemoval="true"itu akan menghapus semua pesanan sebelumnya dan menggantinya dengan yang disediakan. ( PUTdalam hal REST API)

@OneToMany(mappedBy="customer", orphanRemoval="true")
public List<Order> getOrders() { ... }

Tanpa orphanRemovalperintah lama akan disimpan. ( PATCHdalam hal REST API)

garg10may
sumber
1

Karena pertanyaan ini sangat umum, jawaban ini didasarkan pada artikel yang saya tulis di blog saya ini.

CascadeType.REMOVE

The CascadeType.REMOVEstrategi, yang Anda dapat mengkonfigurasi secara eksplisit:

@OneToMany(
    mappedBy = "post",
    cascade = CascadeType.REMOVE
)
private List<PostComment> comments = new ArrayList<>();

atau mewarisi secara implisit dari CascadeType.ALLstrategi:

@OneToMany(
    mappedBy = "post",
    cascade = CascadeType.ALL
)
private List<PostComment> comments = new ArrayList<>();

memungkinkan Anda untuk menyebarkan remove operasi dari entitas induk ke entitas anaknya.

Jadi, jika kita mengambil Postentitas induk beserta commentskoleksinya, dan menghapus postentitas tersebut:

Post post = entityManager.createQuery("""
    select p
    from Post p
    join fetch p.comments
    where p.id = :id
    """, Post.class)
.setParameter("id", postId)
.getSingleResult();

entityManager.remove(post);

Hibernate akan menjalankan tiga pernyataan hapus:

DELETE FROM post_comment 
WHERE id = 2

DELETE FROM post_comment 
WHERE id = 3

DELETE FROM post 
WHERE id = 1

Para PostCommententitas anak yang dihapus karenaCascadeType.REMOVE strategi, yang bertindak seolah-olah kita dihapus entitas anak juga.

Strategi pemindahan anak yatim piatu

Strategi penghapusan yatim piatu, yang perlu disetel melalui orphanRemovalatribut:

@OneToMany(
    mappedBy = "post",
    cascade = CascadeType.ALL,
    orphanRemoval = true
)
private List<PostComment> comments = new ArrayList<>();

memungkinkan Anda untuk menghapus baris tabel anak setelah menghapus entitas anak dari koleksi.

Jadi, jika kita memuat Postentitas bersama dengan commentskoleksinya dan menghapus yang pertama PostCommentdari commentskoleksi:

Post post = entityManager.createQuery("""
    select p
    from Post p
    join fetch p.comments c
    where p.id = :id
    order by p.id, c.id
    """, Post.class)
.setParameter("id", postId)
.getSingleResult();

post.remove(post.getComments().get(0));

Hibernate akan menjalankan pernyataan DELETE untuk post_commentbaris tabel terkait :

DELETE FROM post_comment 
WHERE id = 2

Untuk detail lebih lanjut tentang topik ini, lihat artikel ini juga.

Vlad Mihalcea
sumber