Ý nghĩa của CascadeType.ALL đối với hiệp hội JPM @ManyToOne


210

Tôi nghĩ rằng tôi đã hiểu sai ý nghĩa của tầng trong bối cảnh của một @ManyToOnemối quan hệ.

Trường hợp:

public class User {

   @OneToMany(fetch = FetchType.EAGER)
   protected Set<Address> userAddresses;

}

public class Address {

   @ManyToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
   protected User addressOwner;

}

Ý nghĩa của là cascade = CascadeType.ALLgì? Ví dụ: nếu tôi xóa một địa chỉ nhất định khỏi cơ sở dữ liệu, thực tế là tôi đã thêm cascade = CascadeType.ALLảnh hưởng đến dữ liệu của tôi như thế nào ( Usertôi đoán vậy)?

Câu trả lời:


360

Ý nghĩa của việc CascadeType.ALLlà sự kiên trì sẽ tuyên truyền (xếp tầng) tất cả các EntityManagerhoạt động ( PERSIST, REMOVE, REFRESH, MERGE, DETACH) cho các thực thể liên quan.

Có vẻ như trong trường hợp của bạn là một ý tưởng tồi, vì loại bỏ một cái Addresssẽ dẫn đến loại bỏ những thứ liên quan User. Vì người dùng có thể có nhiều địa chỉ, các địa chỉ khác sẽ trở thành trẻ mồ côi. Tuy nhiên, trường hợp nghịch đảo (chú thích User) sẽ có ý nghĩa - nếu một địa chỉ chỉ thuộc về một người dùng, thì có thể tuyên truyền xóa tất cả các địa chỉ thuộc về người dùng nếu người dùng này bị xóa.

BTW: bạn có thể muốn thêm một mappedBy="addressOwner"thuộc tính để Userbáo hiệu cho nhà cung cấp kiên trì rằng cột tham gia phải nằm trong bảng ADDRESS.


55
+1 cho lời giải thích tốt nhất và ngắn nhất về ánh xạBy tôi từng gặp.
Rực rỡ

4
Mặc dù có thể có CascadeType.ALL ở phía @OneToMany.
mvmn

48

Xem ở đây để biết ví dụ từ các tài liệu OpenJPA. CascadeType.ALLcó nghĩa là nó sẽ làm tất cả các hành động.

Trích dẫn:

CascadeType.PERSIST: Khi duy trì một thực thể, cũng tồn tại các thực thể được giữ trong các trường của nó. Chúng tôi đề xuất một ứng dụng tự do của quy tắc xếp tầng này, bởi vì nếu EntityManager tìm thấy một trường tham chiếu một thực thể mới trong quá trình tuôn ra và trường không sử dụng CascadeType.PERSIST, thì đó là một lỗi.

CascadeType.REMOVE: Khi xóa một thực thể, nó cũng xóa các thực thể được giữ trong trường này.

CascadeType.REFRESH: Khi làm mới một thực thể, cũng làm mới các thực thể được giữ trong trường này.

CascadeType.MERGE: Khi hợp nhất trạng thái thực thể, cũng hợp nhất các thực thể được giữ trong trường này.

Sebastian


4
Mới trong JPA, thông tin này hữu ích nhưng còn Detach ở đây thì sao?
Sarz

1
Trong CascadeType.DETACH, khi tách một thực thể, em cũng tách ra các thực thể được giữ bởi thực thể mẹ.
Dorian Mejer

29

Như tôi đã giải thích trong bài viết này và trong cuốn sách của tôi, hiệu suất cao Java Persistence , bạn không nên sử dụng CascadeType.ALLtrên @ManyToOnekể từ khi chuyển trạng thái thực thể nên tuyên truyền từ các đơn vị chuyên cho những người trẻ, không phải là cách khác xung quanh.

Bên @ManyToOneluôn là hiệp hội Con vì nó ánh xạ cột Khóa ngoài nằm bên dưới.

Do đó, bạn nên chuyển CascadeType.ALLtừ @ManyToOneliên kết sang @OneToManybên, cũng nên sử dụng mappedBythuộc tính vì đây là ánh xạ mối quan hệ bảng một-nhiều hiệu quả nhất .


18

Từ thông số kỹ thuật EJB3.0 :

Việc sử dụng phần tử chú thích theo tầng có thể được sử dụng để truyền bá tác động của một hoạt động đến các thực thể liên quan. Chức năng xếp tầng thường được sử dụng nhất trong các mối quan hệ cha-con.

Nếu X là một thực thể được quản lý, thao tác gỡ bỏ sẽ khiến nó bị xóa. Thao tác xóa được xếp tầng cho các thực thể được tham chiếu bởi X, nếu các mối quan hệ từ X đến các thực thể khác này được chú thích với cascade = REMOVE hoặc cascade = ALL giá trị phần tử chú thích.

Vì vậy, một cách ngắn gọn, các mối quan hệ thực thể được xác định với CascadeType.Allsẽ đảm bảo rằng tất cả các sự kiện dai dẳng như tồn tại, làm mới, hợp nhất và loại bỏ xảy ra trên cha mẹ, sẽ được truyền cho con. Việc xác định các CascadeTypetùy chọn khác cung cấp cho nhà phát triển mức độ kiểm soát chi tiết hơn về cách liên kết thực thể xử lý tính bền bỉ.

Ví dụ: nếu tôi có một đối tượng Sách có chứa Danh sách các trang và tôi thêm một đối tượng trang trong danh sách này. Nếu @OneToManychú thích xác định liên kết giữa Sách và Trang được đánh dấu là CascadeType.All, việc duy trì Sách sẽ dẫn đến Trang cũng được lưu vào cơ sở dữ liệu.


11

Trong JPA 2.0 nếu bạn muốn xóa một địa chỉ nếu bạn xóa địa chỉ đó khỏi thực thể Người dùng, bạn có thể thêm orphanRemoval=true(thay vì CascadeType.REMOVE) vào địa chỉ của mình @OneToMany.

Giải thích thêm giữa orphanRemoval=trueCascadeType.REMOVEở đây .


4

Nếu bạn chỉ muốn xóa địa chỉ được gán cho người dùng và không ảnh hưởng đến lớp thực thể Người dùng, bạn nên thử một cái gì đó như thế:

@Entity
public class User {
   @OneToMany(mappedBy = "addressOwner", cascade = CascadeType.ALL)
   protected Set<Address> userAddresses = new HashSet<>();
}

@Entity 
public class Addresses {
   @ManyToOne(cascade = CascadeType.REFRESH) @JoinColumn(name = "user_id")
   protected User addressOwner;
}

Bằng cách này, bạn không cần phải lo lắng về việc sử dụng tìm nạp trong các chú thích. Nhưng hãy nhớ khi xóa Người dùng, bạn cũng sẽ xóa địa chỉ được kết nối với đối tượng người dùng.

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.