Sự khác biệt giữa CascadeType.REMOVE và orphanRemoval trong JPA là gì?


100

Sự khác biệt giữa

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

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

Ví dụ này là từ Hướng dẫn sử dụng Java EE, nhưng tôi vẫn chưa hiểu chi tiết.


Loại bỏ mồ côi có nghĩa là các thực thể phụ thuộc bị xóa khi mối quan hệ với thực thể "mẹ" của chúng bị hủy.
Rahul Tripathi

1
Đã viết một trường hợp thử nghiệm có thể minh họa khái niệm.
Martin Andersson

Câu trả lời:


152

Từ đây : -

Xếp tầng Loại bỏ

Đánh dấu trường tham chiếu bằng CascadeType.REMOVE (hoặc CascadeType.ALL, bao gồm REMOVE) cho biết rằng các thao tác loại bỏ phải được tự động xếp tầng tới các đối tượng thực thể được tham chiếu bởi trường đó (nhiều đối tượng thực thể có thể được tham chiếu bởi một trường tập hợp):

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

Loại bỏ trẻ mồ côi

JPA 2 hỗ trợ chế độ xếp tầng loại bỏ bổ sung và tích cực hơn có thể được chỉ định bằng cách sử dụng phần tử orphanRemoval của chú thích @OneToOne và @OneToMany:

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

SỰ KHÁC BIỆT:-

Sự khác biệt giữa hai cài đặt là phản ứng với việc ngắt kết nối mối quan hệ. Ví dụ, chẳng hạn như khi đặt trường địa chỉ thành null hoặc đối tượng Địa chỉ khác.

  • Nếu orphanRemoval = true được chỉ định, thể hiện Địa chỉ bị ngắt kết nối sẽ tự động bị xóa. Điều này hữu ích để làm sạch các đối tượng phụ thuộc (ví dụ: Địa chỉ) không nên tồn tại mà không có tham chiếu từ đối tượng chủ sở hữu (ví dụ: Nhân viên).
  • Nếu chỉ cascade = CascadeType.REMOVE được chỉ định thì không có hành động tự động nào được thực hiện vì ngắt kết nối mối quan hệ không phải là
    thao tác xóa .

87

Một cách dễ dàng để hiểu sự khác biệt giữa CascadeType.REMOVEorphanRemoval=true.

Đối với loại bỏ mồ côi: Nếu bạn gọi setOrders(null), các Orderthực thể liên quan sẽ tự động bị xóa trong db.

Đối với loại bỏ thác: Nếu bạn gọi setOrders(null), các Orderthực thể liên quan sẽ KHÔNG bị xóa trong db tự động.


2
loại bỏ === xóa
Abdull

9

Giả sử chúng ta có một thực thể con và một thực thể mẹ. Cha mẹ có thể có nhiều con.

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

OrphanRemoval là một khái niệm ORM, nó cho biết đứa trẻ có mồ côi hay không. nó cũng nên được xóa khỏi cơ sở dữ liệu.

Một đứa trẻ mồ côi khi nó không thể được truy cập từ cha mẹ của nó. Ví dụ: nếu chúng ta xóa tập hợp các đối tượng Person (đặt nó thành một tập hợp trống) hoặc thay thế nó bằng một tập hợp mới thì cha mẹ không còn có thể truy cập vào những đứa trẻ trong tập hợp cũ và những đứa trẻ bị mồ côi, vì vậy những đứa trẻ sẽ phải chịu cũng bị loại bỏ trong cơ sở dữ liệu.

CascadeType.REMOVE là một khái niệm mức cơ sở dữ liệu và nó cho biết nếu cha mẹ bị xóa, tất cả các bản ghi liên quan của nó trong bảng con sẽ bị xóa.


2

Thực tế, sự khác biệt nằm ở việc bạn đang cố gắng cập nhật dữ liệu (PATCH) hay thay thế hoàn toàn dữ liệu (PUT)

Giả sử bạn xóa customerso với việc sử dụng cascade=REMOVEcũng sẽ xóa các đơn đặt hàng của khách hàng có vẻ như có ý định và hữu ích.

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

Bây giờ, giả sử bạn cập nhật a customervới orphanRemoval="true"nó sẽ xóa tất cả các đơn đặt hàng trước đó và thay thế chúng bằng đơn hàng được cung cấp. ( PUTvề mặt REST API)

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

Nếu không có orphanRemovalđơn đặt hàng cũ sẽ được giữ. ( PATCHvề mặt REST API)


1

Vì câu hỏi này rất phổ biến, câu trả lời này dựa trên bài viết này tôi đã viết trên blog của mình.

CascadeType.REMOVE

Các CascadeType.REMOVEchiến lược, mà bạn có thể cấu hình một cách rõ ràng:

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

hoặc kế thừa nó ngầm từ CascadeType.ALLchiến lược:

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

cho phép bạn truyền removehoạt động từ thực thể mẹ sang các thực thể con của nó.

Vì vậy, nếu chúng tôi tìm nạp Postthực thể mẹ cùng với commentsbộ sưu tập của nó và xóa postthực thể:

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 sẽ thực thi ba câu lệnh xóa:

DELETE FROM post_comment 
WHERE id = 2

DELETE FROM post_comment 
WHERE id = 3

DELETE FROM post 
WHERE id = 1

Các PostCommentthực thể con đã bị xóa do CascadeType.REMOVEchiến lược này hoạt động như thể chúng tôi cũng xóa các thực thể con.

Chiến lược loại bỏ trẻ mồ côi

Chiến lược loại bỏ trẻ mồ côi, cần được đặt thông qua orphanRemovalthuộc tính:

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

cho phép bạn xóa hàng bảng con khi xóa thực thể con khỏi bộ sưu tập.

Vì vậy, nếu chúng tôi tải Postđối tượng cùng với commentsbộ sưu tập của nó và xóa đối tượng đầu tiên PostCommentkhỏi commentsbộ sưu tập:

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 sẽ thực thi một câu lệnh DELETE cho post_commenthàng bảng được liên kết :

DELETE FROM post_comment 
WHERE id = 2

Để biết thêm chi tiết về chủ đề này, hãy xem bài viết này .

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.