CascadeType.ALL มีความหมายอย่างไรสำหรับสมาคม @ManyToOne JPA


210

ฉันคิดว่าฉันเข้าใจความหมายของการเรียงซ้อนในบริบทของ@ManyToOneความสัมพันธ์

กรณี:

public class User {

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

}

public class Address {

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

}

ความหมายของcascade = CascadeType.ALLคืออะไร? ตัวอย่างเช่นหากฉันลบที่อยู่บางอย่างจากฐานข้อมูลความจริงที่ว่าฉันเพิ่มที่cascade = CascadeType.ALLมีผลต่อข้อมูลของฉัน (ที่Userฉันเดา)?

คำตอบ:


360

ความหมายของCascadeType.ALLคือการติดตาจะเผยแพร่ (น้ำตก) EntityManagerการดำเนินงานทั้งหมด( PERSIST, REMOVE, REFRESH, MERGE, DETACH) ไปยังหน่วยงานที่เกี่ยวข้อง

ดูเหมือนว่าในกรณีของคุณจะเป็นความคิดที่ไม่ดีเป็นลบจะนำไปสู่การลบที่เกี่ยวข้องAddress Userเนื่องจากผู้ใช้สามารถมีที่อยู่หลายแห่งที่อยู่อื่นจะกลายเป็นเด็กกำพร้า อย่างไรก็ตามกรณีผกผัน (คำอธิบายประกอบUser) จะสมเหตุสมผล - หากที่อยู่เป็นของผู้ใช้คนเดียวเท่านั้นมันมีความปลอดภัยในการเผยแพร่การลบที่อยู่ทั้งหมดที่เป็นของผู้ใช้ถ้าผู้ใช้นี้จะถูกลบ

BTW: คุณอาจต้องการเพิ่มแอmappedBy="addressOwner"ททริบิวของคุณUserเพื่อส่งสัญญาณไปยังผู้ให้บริการที่มีอยู่ที่คอลัมน์เข้าร่วมควรอยู่ในตาราง ADDRESS


55
+1 สำหรับคำอธิบายที่ดีที่สุดและสั้นที่สุดของแมปโดยฉันเคยเจอมา
Ridcully

4
มันอาจจะดีถ้ามี CascadeType.ALL ที่ @OneToMany
mvmn

48

ดูที่นี่สำหรับตัวอย่างจากเอกสาร OpenJPA CascadeType.ALLหมายความว่ามันจะทำทุกอย่าง

อ้างถึง:

CascadeType.PERSIST: เมื่อยังคงเอนทิตีอยู่ให้คงเอนทิตีที่อยู่ในฟิลด์ เราแนะนำให้ใช้แอปพลิเคชันแบบเสรีของกฎการเรียงซ้อนนี้เนื่องจากหาก EntityManager ค้นหาเขตข้อมูลที่อ้างอิงถึงเอนทิตีใหม่ในระหว่างการล้างข้อมูลและฟิลด์ไม่ได้ใช้ CascadeType.PERSIST มันเป็นข้อผิดพลาด

CascadeType.REMOVE: เมื่อลบเอนทิตีมันจะลบเอนทิตีที่อยู่ในฟิลด์นี้

CascadeType.REFRESH: เมื่อรีเฟรชเอนทิตีให้รีเฟรชเอนทิตีที่อยู่ในฟิลด์นี้ด้วย

CascadeType.MERGE: เมื่อรวมสถานะเอนทิตีแล้วให้รวมเอนทิตีที่อยู่ในฟิลด์นี้ด้วย

เซบาสเตียน


4
ใหม่ใน JPA ข้อมูลนี้มีประโยชน์ แต่แล้ว Detach ที่นี่ล่ะ
Sarz

1
ใน CascadeType.DETACH เมื่อดึงเอนทิตี้ออก em ยังแยกเอนทิตีที่ถูกยึดโดยเอนทิตีหลัก
Dorian Mejer

29

ขณะที่ผมได้อธิบายไว้ในบทความนี้และในหนังสือของฉันประสิทธิภาพสูง Java คงทน , คุณไม่ควรใช้CascadeType.ALLใน@ManyToOneตั้งแต่เปลี่ยนสถานะนิติบุคคลควรเผยแพร่จากหน่วยงานผู้ปกครองกับคนที่เด็กไม่ได้เป็นวิธีอื่น ๆ รอบ ๆ

@ManyToOneด้านข้างอยู่เสมอสมาคมเด็กตั้งแต่แผนที่พื้นฐานคอลัมน์ต่างประเทศที่สำคัญ

ดังนั้นคุณควรย้ายCascadeType.ALLจาก@ManyToOneสมาคมไป@OneToManyด้านข้างซึ่งยังควรใช้mappedByแอตทริบิวต์เนื่องจากมันทำแผนที่ความสัมพันธ์ของตารางที่มีประสิทธิภาพมากที่สุดคนหนึ่งต่อหลายคน


18

จากข้อกำหนด EJB3.0 :

การใช้องค์ประกอบคำอธิบายประกอบแบบเรียงซ้อนอาจใช้เพื่อเผยแพร่ผลกระทบของการดำเนินการไปยังเอนทิตีที่เกี่ยวข้อง ฟังก์ชันการเรียงซ้อนส่วนใหญ่จะใช้ในความสัมพันธ์ระหว่างพ่อแม่และลูก

หาก X เป็นเอนทิตีที่ได้รับการจัดการการดำเนินการลบจะทำให้เกิดการลบ การดำเนินการลบจะเรียงลำดับตามเอนทิตีที่อ้างอิงโดย X หากความสัมพันธ์จาก X ไปยังเอนทิตีอื่น ๆ เหล่านี้มีการเพิ่มความคิดเห็นด้วย cascade = REMOVE หรือ cascade = ค่าการเพิ่มความคิดเห็นประกอบ

ดังนั้นโดยสรุปความสัมพันธ์ของเอนทิตีที่กำหนดด้วยCascadeType.Allจะช่วยให้มั่นใจได้ว่าเหตุการณ์การคงอยู่ทั้งหมดเช่นการคงอยู่, รีเฟรช, ผสานและลบที่เกิดขึ้นบนพาเรนต์จะถูกส่งผ่านไปยังเด็ก การกำหนดCascadeTypeตัวเลือกอื่นให้นักพัฒนามีระดับการควบคุมที่ละเอียดยิ่งขึ้นเกี่ยวกับวิธีที่การเชื่อมโยงเอนทิตีจัดการกับการคงอยู่

ตัวอย่างเช่นถ้าฉันมีวัตถุหนังสือที่มีรายการหน้าและฉันเพิ่มวัตถุหน้าภายในรายการนี้ หาก@OneToManyคำอธิบายประกอบที่กำหนดความสัมพันธ์ระหว่าง Book กับ Page ถูกทำเครื่องหมายว่าการCascadeType.Allคงอยู่ของ Book จะส่งผลให้เพจนั้นยังคงอยู่ในฐานข้อมูล


11

ใน JPA 2.0 หากคุณต้องการลบที่อยู่หากคุณลบมันออกจากเอนทิตีผู้ใช้คุณสามารถเพิ่มorphanRemoval=true(แทนCascadeType.REMOVE) ลงในของคุณ@OneToManyเพื่อคุณ

คำอธิบายเพิ่มเติมระหว่างorphanRemoval=trueและCascadeType.REMOVEเป็นที่นี่


4

หากคุณต้องการลบที่อยู่ที่กำหนดให้กับผู้ใช้และไม่ส่งผลกระทบต่อคลาสเอนทิตีของผู้ใช้คุณควรลองทำสิ่งต่อไปนี้:

@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;
}

วิธีนี้คุณไม่จำเป็นต้องกังวลเกี่ยวกับการใช้การดึงข้อมูลในคำอธิบายประกอบ แต่จำไว้ว่าเมื่อลบผู้ใช้คุณจะลบที่อยู่ที่เชื่อมต่อไปยังวัตถุผู้ใช้

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