JPA OneToMany ไม่ได้ลบเด็ก


158

ฉันมีปัญหากับการ@OneToManyแม็พแบบง่าย ๆระหว่างพาเรนต์และเอนทิตีย่อย ทั้งหมดทำงานได้ดีมีเพียงบันทึกของเด็กที่ไม่ถูกลบเมื่อฉันลบออกจากคอลเลกชัน

ผู้ปกครอง:

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

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

 ...
}

เด็ก:

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

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

  ...
}

ถ้าตอนนี้ฉันลบและลูกออกจากชุดลูกมันจะไม่ถูกลบออกจากฐานข้อมูล ฉันพยายามลบล้างการchild.parentอ้างอิง แต่มันก็ไม่ได้ผลเหมือนกัน

เอนทิตีที่ใช้ในเว็บแอปพลิเคชันการลบที่เกิดขึ้นเป็นส่วนหนึ่งของคำขอ Ajax ฉันไม่มีรายการลูกที่ถูกลบเมื่อกดปุ่มบันทึกดังนั้นฉันจึงไม่สามารถลบได้โดยปริยาย

คำตอบ:


253

พฤติกรรมของ JPA นั้นถูกต้อง (หมายถึงตามข้อกำหนด ): วัตถุจะไม่ถูกลบเพียงเพราะคุณลบพวกมันออกจากคอลเลกชัน OneToMany มีส่วนขยายเฉพาะผู้ขายที่ทำเช่นนั้น แต่ JPA ดั้งเดิมไม่รองรับ

ในส่วนนี้เป็นเพราะ JPA ไม่ทราบว่าควรลบบางสิ่งที่ลบออกจากคอลเลกชันหรือไม่ ในแง่การสร้างแบบจำลองวัตถุนี้เป็นความแตกต่างระหว่างองค์ประกอบและ "การรวม *

ในองค์ประกอบกิจการเด็กไม่เคยมีใครมีชีวิตอยู่ได้โดยไม่ต้องปกครอง ตัวอย่างคลาสสิกอยู่ระหว่างบ้านและห้อง ลบบ้านและห้องก็ไปด้วย

การรวมตัวเป็นสมาคมที่หลวมและถูกพิมพ์โดยหลักสูตรและนักเรียน ลบหลักสูตรและนักเรียนยังคงมีอยู่ (อาจอยู่ในหลักสูตรอื่น ๆ )

ดังนั้นคุณต้องใช้ส่วนขยายเฉพาะผู้ขายเพื่อบังคับใช้พฤติกรรมนี้ (ถ้ามี) หรือลบชายด์อย่างชัดเจนและลบออกจากคอลเลกชันของผู้ปกครอง

ฉันรู้:


ขอบคุณคำอธิบายที่ดี มันเป็นอย่างที่ฉันกลัว (ฉันทำการค้นหา / อ่านก่อนฉันถามเพียงต้องการบันทึก) อย่างใดฉันเริ่มเสียใจการตัดสินใจที่จะใช้ JPA API และ nit Hibernate โดยตรง .. ฉันจะลองตัวชี้จันทรา Patni และใช้โหมดจำศีล delete_orphan จำศีล
bert

ฉันมีคำถามคล้าย ๆ กันเกี่ยวกับเรื่องนี้ จะกรุณาดูที่โพสต์นี้ที่นี่โปรด? stackoverflow.com/questions/4569857/…
Thang Pham

77
ด้วย JPA 2.0 ตอนนี้คุณสามารถใช้ออปชั่น orphanRemoval = true
itsadok

2
คำอธิบายเบื้องต้นที่ดีและคำแนะนำที่ดีเกี่ยวกับ orphanRemoval ไม่มีความคิดว่า JPA ไม่ได้คิดว่าเป็นการลบประเภทนี้ ความแตกต่างระหว่างสิ่งที่ฉันรู้เกี่ยวกับไฮเบอร์เนตและสิ่งที่ JPA จริงสามารถทำให้โกรธได้
sma

อธิบายอย่างชัดเจนโดยการเปิดเผยความแตกต่างระหว่างองค์ประกอบและการเกรเกต!
Felipe Leão

73

นอกเหนือจากคำตอบของ cletus JPA 2.0ซึ่งเป็นขั้นสุดท้ายตั้งแต่เดือนธันวาคม 2010 ยังมีorphanRemovalคุณลักษณะเกี่ยวกับ@OneToManyคำอธิบายประกอบ สำหรับรายละเอียดเพิ่มเติมดูบล็อกนี้

โปรดทราบว่าเนื่องจากข้อมูลจำเพาะค่อนข้างใหม่ผู้ให้บริการ JPA 1 ทั้งหมดจึงไม่มีการใช้งาน JPA 2 ขั้นสุดท้าย ตัวอย่างเช่นรุ่นHibernate 3.5.0-Beta-2ยังไม่รองรับคุณสมบัตินี้


รายการบล็อก - ลิงก์เสียหาย
Steffi

1
และความมหัศจรรย์ของเครื่อง
เวย์แบ็

43

คุณสามารถลองสิ่งนี้:

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


2
ขอบคุณ แต่คำถามกลับมาจาก JPA 1 ครั้ง และตัวเลือกนี้ไม่สามารถใช้ได้กลับกว่า
bert

9
ดีที่จะรู้ แต่สำหรับพวกเราที่ค้นหาวิธีการแก้ปัญหานี้ใน JPA2 ครั้ง :)
alex440

20

ตามที่อธิบายไว้เป็นไปไม่ได้ที่จะทำสิ่งที่ฉันต้องการกับ JPA ดังนั้นฉันจึงใช้คำอธิบายประกอบ hibernate.cascade ด้วยสิ่งนี้รหัสที่เกี่ยวข้องในคลาสผู้ปกครองจะมีลักษณะดังนี้:

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

ฉันไม่สามารถใช้ 'ทั้งหมด' ได้อย่างง่ายเพราะจะเป็นการลบพาเรนต์ด้วย


4

น้ำตกที่นี่ในบริบทของการลบหมายความว่าเด็ก ๆ จะถูกลบหากคุณลบผู้ปกครอง ไม่ใช่สมาคม หากคุณกำลังใช้ Hibernate เป็นผู้ให้บริการ JPA ของคุณคุณสามารถทำได้โดยใช้น้ำตกที่เฉพาะเจาะจงจำศีล



โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.