JPA OneToMany không xóa con


158

Tôi có một vấn đề với @OneToManyánh xạ đơn giản giữa cha mẹ và thực thể con. Tất cả đều hoạt động tốt, chỉ có điều hồ sơ con không bị xóa khi tôi xóa chúng khỏi bộ sưu tập.

Phụ huynh:

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

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

 ...
}

Đứa trẻ:

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

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

  ...
}

Nếu bây giờ tôi xóa và con từ Set con, nó sẽ không bị xóa khỏi cơ sở dữ liệu. Tôi đã cố gắng vô hiệu hóa child.parenttài liệu tham khảo, nhưng nó cũng không hoạt động.

Các thực thể được sử dụng trong một ứng dụng web, việc xóa xảy ra như một phần của yêu cầu Ajax. Tôi không có danh sách những đứa trẻ bị xóa khi nhấn nút lưu, vì vậy tôi không thể xóa chúng hoàn toàn.

Câu trả lời:


252

Hành vi của JPA là chính xác (có nghĩa là theo thông số kỹ thuật ): các đối tượng không bị xóa đơn giản vì bạn đã xóa chúng khỏi bộ sưu tập OneToMany. Có các tiện ích mở rộng dành riêng cho nhà cung cấp thực hiện điều đó nhưng JPA bản địa không phục vụ cho nó.

Một phần điều này là do JPA không thực sự biết liệu có nên xóa thứ gì đó đã bị xóa khỏi bộ sưu tập hay không. Trong thuật ngữ mô hình đối tượng, đây là sự khác biệt giữa thành phần và "tập hợp *.

Trong thành phần , thực thể con không tồn tại mà không có cha mẹ. Một ví dụ kinh điển là giữa Nhà và Phòng. Xóa nhà và các phòng đi quá.

Tập hợp là một loại liên kết lỏng lẻo hơn và được tiêu biểu bởi Khóa học và Sinh viên. Xóa Khóa học và Học sinh vẫn tồn tại (có thể trong các Khóa học khác).

Vì vậy, bạn cần sử dụng các tiện ích mở rộng dành riêng cho nhà cung cấp để buộc hành vi này (nếu có) hoặc xóa rõ ràng con VÀ xóa nó khỏi bộ sưu tập của cha mẹ.

Tôi biết:


cảm ơn lời giải thích tốt đẹp Vì vậy, nó là như tôi sợ. (tôi đã thực hiện một số tìm kiếm / đọc trước khi tôi yêu cầu, chỉ muốn được lưu). bằng cách nào đó tôi bắt đầu hối hận về quyết định sử dụng trực tiếp API JPA và nit Hibernate .. Tôi sẽ thử con trỏ Chandra Patni và sử dụng loại tầng xóa hibernate xóa_orphan.
bert

Tôi có một loại câu hỏi tương tự về điều này. Xin vui lòng xem bài viết này ở đây, xin vui lòng? stackoverflow.com/questions/4569857/ từ
Thắng Phạm

77
Với JPA 2.0, bây giờ bạn có thể sử dụng tùy chọn orphanRemoval = true
itsadok

2
Giải thích ban đầu tuyệt vời và lời khuyên tốt về orphanRemoval. Không có ý tưởng JPA đã không giải thích cho loại bỏ này. Các sắc thái giữa những gì tôi biết về Hibernate và những gì JPA thực sự có thể làm điên cuồng.
sma

Giải thích cặn kẽ bằng cách phơi bày sự khác biệt giữa Thành phần và Kết hợp!
Felipe Leão

73

Ngoài câu trả lời của cletus, JPA 2.0 , cuối cùng kể từ tháng 12 năm 2010, giới thiệu một orphanRemovalthuộc tính trên @OneToManycác chú thích. Để biết thêm chi tiết xem mục blog này .

Lưu ý rằng vì thông số kỹ thuật tương đối mới, không phải tất cả nhà cung cấp JPA 1 đều có triển khai JPA 2 cuối cùng. Ví dụ: bản phát hành Hibernate 3.5.0-Beta-2 chưa hỗ trợ thuộc tính này.


mục blog - liên kết bị hỏng.
Steffi

1
Và sự kỳ diệu của máy Wayback cứu độ chúng ta: web.archive.org/web/20120225040254/http://javablog.co.uk/2009/...
Louis Jacomet

43

Bạn có thể thử điều này:

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


2
Cảm ơn. Nhưng câu hỏi đã trở lại từ JPA 1 lần. Và tùy chọn này không có sẵn trở lại.
bert

9
tuy nhiên, thật tốt khi biết những người tìm kiếm giải pháp cho vấn đề này trong JPA2 lần :)
alex440

20

Như đã giải thích, không thể thực hiện những gì tôi muốn với JPA, vì vậy tôi đã sử dụng chú thích hibernate.cascade, với điều này, mã có liên quan trong lớp Parent bây giờ trông như thế này:

@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>();

Tôi không thể đơn giản sử dụng 'TẤT CẢ' vì điều này cũng sẽ xóa cha mẹ.


4

Ở đây thác, trong bối cảnh loại bỏ, có nghĩa là trẻ em bị loại bỏ nếu bạn loại bỏ cha mẹ. Không phải hiệp hội. Nếu bạn đang sử dụng Hibernate làm nhà cung cấp JPA của mình, bạn có thể thực hiện bằng cách sử dụng tầng cụ thể ngủ đông .


4

Bạn có thể thử điều này:

@OneToOne(cascade = CascadeType.REFRESH) 

hoặc là

@OneToMany(cascade = CascadeType.REFRESH)

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.