जेपीए अनाथमेवोवाल कैसे सच होता है = DELETE CASCADE DML क्लॉज से अलग


184

मैं JPA 2.0 orphanRemovalविशेषता के बारे में थोड़ा भ्रमित हूं ।

मुझे लगता है कि जब मैं अपने JPA प्रदाता के DB पीढ़ी के टूल का उपयोग करता हूं, तो यह देख सकता हूं कि किसी ON DELETE CASCADEविशेष संबंध के लिए अंतर्निहित डेटाबेस DDL बनाने के लिए ।

हालाँकि, यदि DB मौजूद है और इसका पहले से ही ON DELETE CASCADEसंबंध है, तो क्या यह विलोपन को उचित तरीके से रोकने के लिए पर्याप्त नहीं है? orphanRemovalइसके अलावा क्या करता है ?

चियर्स

जवाबों:


291

orphanRemovalकुछ नहीं करना है ON DELETE CASCADE

orphanRemovalएक पूरी तरह से ओआरएम-विशिष्ट चीज है । यह "चाइल्ड" इकाई को हटा दिया जाता है जब इसे "पैरेंट" इकाई से संदर्भित नहीं किया जाता है, उदाहरण के लिए जब आप चाइल्ड यूनिट को पेरेंट यूनिट के संबंधित संग्रह से हटाते हैं।

ON DELETE CASCADEएक डेटाबेस-विशिष्ट चीज़ है , यह डेटाबेस में "चाइल्ड" पंक्ति को हटाता है जब "पैरेंट" पंक्ति हटा दी जाती है।


3
क्या इसका मतलब यह है कि उनके पास सुरक्षित प्रभाव है, लेकिन इसे बनाने के लिए एक अलग प्रणाली जिम्मेदार है?
अनाम

101
आनन, इसका प्रभाव समान नहीं है। पैरेंट डिलीट होने पर सभी चाइल्ड रिकॉर्ड को डिलीट करने के लिए DELETE CASCADE पर DB बताता है। यदि मैं INVOICE को हटाता हूं, तो उस INVOICE पर सभी ITEMS हटा दें। OrphanRemoval ORM से कहता है कि अगर मैं किसी आइटम को उस आइटम के संग्रह से हटाता हूं, जो किसी इनवॉइस ऑब्जेक्ट (मेमोरी ऑपरेशन में) से संबंधित है, और फिर चालान को "सेव" करें, तो हटाए गए आइटम को अंतर्निहित DB से हटा दिया जाना चाहिए।
garyKeorkunian

2
यदि आप एक-दिशात्मक संबंध का उपयोग करते हैं, तो अनाथ को स्वचालित रूप से हटा दिया जाएगा, भले ही आप orphanRemoval सेट न करें
टिम

98

एक उदाहरण यहाँ लिया गया है :

जब कोई Employeeनिकाय ऑब्जेक्ट हटा दिया जाता है, तो हटाए गए ऑपरेशन को संदर्भित Addressइकाई ऑब्जेक्ट पर कैस्केड किया जाता है । इस संबंध में, orphanRemoval=trueऔर cascade=CascadeType.REMOVEसमान हैं, और यदि orphanRemoval=trueनिर्दिष्ट किया गया है, CascadeType.REMOVEनिरर्थक है।

दो सेटिंग्स के बीच का अंतर एक रिश्ते को डिस्कनेक्ट करने की प्रतिक्रिया में है। उदाहरण के लिए, जैसे पता फ़ील्ड सेट करते समय nullया किसी अन्य Addressऑब्जेक्ट पर।

  • यदि orphanRemoval=trueनिर्दिष्ट किया गया है तो डिस्कनेक्ट किया गया Addressउदाहरण स्वचालित रूप से हटा दिया जाता है। यह निर्भर वस्तुओं (जैसे Address) की सफाई के लिए उपयोगी है जो किसी स्वामी ऑब्जेक्ट (उदाहरण Employee) के संदर्भ के बिना मौजूद नहीं होना चाहिए ।

  • यदि केवल cascade=CascadeType.REMOVEनिर्दिष्ट किया गया है, तो कोई भी स्वचालित कार्रवाई नहीं की जाती है क्योंकि किसी संबंध को डिस्कनेक्ट करने के लिए निकालें ऑपरेशन नहीं है।

अनाथ निष्कासन के परिणामस्वरूप झूलते संदर्भों से बचने के लिए, यह सुविधा केवल उन क्षेत्रों के लिए सक्षम होनी चाहिए जो निजी गैर-साझा आश्रित वस्तुओं को रखते हैं।

मुझे उम्मीद है कि यह इसे और अधिक स्पष्ट करता है।


आपके उत्तर को पढ़ने के बाद, मुझे उन दोनों के बीच सटीक अंतर का एहसास हुआ और मेरे मुद्दे का समाधान हो गया। मैं डेटाबेस से बाल संस्थाओं को हटाने में फंस गया, अगर वे मूल इकाई में परिभाषित संग्रह से डिस्कनेक्ट (हटाए गए) हैं। उसी के लिए मैंने प्रश्न पूछा ' stackoverflow.com/questions/15526440/… '। दोनों प्रश्नों को जोड़ने के लिए बस अपनी टिप्पणी जोड़ रहा हूं।
नरेंद्र वर्मा


46

जिस क्षण आप संग्रह से एक बाल इकाई निकालते हैं, आप उस बाल इकाई को डीबी से भी हटा देंगे। orphanRemoval का अर्थ है कि आप माता-पिता को नहीं बदल सकते हैं; यदि ऐसा कोई विभाग है, जिसमें कर्मचारी हैं, तो एक बार जब आप उस कर्मचारी को किसी अन्य पुनर्वितरण में डालते हैं, तो आप अनजाने में उस कर्मचारी को डीबी से फ्लश / कमिट (जो भी पहले आता है) को हटा देंगे। मनोबल अनाथमृवल को तब तक के लिए सही साबित करना है जब तक आप निश्चित हैं कि उस माता-पिता के बच्चे अपने पूरे अस्तित्व में एक अलग माता-पिता के पास नहीं जाएंगे। अनाथरेमोवाल को चालू करने से स्वचालित रूप से कैस्केड सूची में REMOVE जुड़ जाता है।


3
बिल्कुल सही ... इसे "निजी" माता-पिता / बाल संबंध भी कहा जाता है।
एचडीवे

इसका मतलब है कि जैसे ही मैं कॉल करता हूं department.remove(emp);कि कर्मचारी को बिना कॉल किए भी commit()
एम्पायर

18

DDL के लिए बराबर JPA मैपिंग ON DELETE CASCADEहै cascade=CascadeType.REMOVE। अनाथ निष्कासन का मतलब है कि आश्रित निकाय को हटा दिया जाता है जब उनके "माता-पिता" इकाई से संबंध नष्ट हो जाते हैं। उदाहरण के लिए अगर किसी बच्चे को @OneToManyइकाई प्रबंधक में बिना किसी खोज के किसी रिश्ते से हटा दिया जाता है ।


1
cascade=CascadeType.REMOVEके बराबर नहीं है ON DELETE CASCADE। एप्लिकेशन कोड में हटा दें और डीडीएल, डीबी में निष्पादित अन्य को प्रभावित नहीं करता है। देखें stackoverflow.com/a/19696859/548473
ग्रिगोरी किसलिन

9

अंतर यह है:
- orphanRemoval = true: "चाइल्ड" निकाय को हटा दिया जाता है जब इसे अब संदर्भित नहीं किया जाता है (इसके अभिभावक को हटाया नहीं जा सकता है)।
- CascadeType.REMOVE: "चाइल्ड" संस्था को तभी हटाया जाता है जब उसका "पैरेंट" हटा दिया जाता है।


6

चूंकि यह एक बहुत ही सामान्य प्रश्न है, इसलिए मैंने यह लेख लिखा है , जिस पर यह उत्तर आधारित है।

इकाई अवस्था परिवर्तन

JPA, INSERT, UPDATE या DELETE जैसे SQL स्टेटमेंट में इकाई स्टेट ट्रांज़िशन का अनुवाद करता है।

जेपीए इकाई राज्य परिवर्तन

जब आप persistएक इकाई होते हैं EntityManager, तो आप फ्लश होने पर निष्पादित किए जाने वाले INSERT स्टेटमेंट को शेड्यूल कर रहे हैं , या तो स्वचालित रूप से या मैन्युअल रूप से।

जब आप removeएक इकाई होते हैं, तो आप DELETE स्टेटमेंट को शेड्यूल कर रहे होते हैं, जिसे पर्सिस्टेंस कॉन्टेक्स्ट के फ्लश होने पर निष्पादित किया जाएगा।

कैस्केडिंग इकाई राज्य परिवर्तन

सुविधा के लिए, जेपीए आपको अभिभावक संस्थाओं से बच्चे के लिए इकाई के राज्य संक्रमण का प्रचार करने की अनुमति देता है।

इसलिए, यदि आपके पास एक अभिभावक Postसंस्था है , जिसका बाल संस्था से @OneToManyजुड़ाव हैPostComment :

पोस्ट और पोस्टकॉममेंट इकाइयाँ

commentsमें संग्रह Postइकाई के रूप में निम्नानुसार मैप किया गया है:

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

CascadeType.ALL

cascadeविशेषता जेपीए प्रदाता बताता है माता पिता से इकाई राज्य संक्रमण पारित करने के लिए Postसभी के लिए इकाई PostCommentमें निहित संस्थाओंcomments संग्रह।

इसलिए, यदि आप Postइकाई को हटाते हैं :

Post post = entityManager.find(Post.class, 1L);
assertEquals(2, post.getComments().size());

entityManager.remove(post);

JPA प्रदाता PostCommentपहले इकाई को निकालने जा रहा है , और जब सभी बाल निकाय हटा दिए जाते हैं, तो यह Postइकाई को भी हटा देगा :

DELETE FROM post_comment WHERE id = 1
DELETE FROM post_comment WHERE id = 2

DELETE FROM post WHERE id = 1

अनाथ निकालना

जब आप orphanRemovalविशेषता सेट करते हैं true, तो JPA प्रदाता एक शेड्यूल करने वाला हैremove ऑपरेशन जब चाइल्ड एंटिटी को संग्रह से हटा दिया जाता है।

तो, हमारे मामले में,

Post post = entityManager.find(Post.class, 1L);
assertEquals(2, post.getComments().size());

PostComment postComment = post.getComments().get(0);
assertEquals(1L, postComment.getId());

post.getComments().remove(postComment);

JPA प्रदाता संबंधित post_commentरिकॉर्ड को हटाने जा रहा है क्योंकि PostCommentइकाई अब commentsसंग्रह में संदर्भित नहीं है :

DELETE FROM post_comment WHERE id = 1

DELETE CASCADE पर

ON DELETE CASCADEFK स्तर पर परिभाषित किया गया है:

ALTER TABLE post_comment 
ADD CONSTRAINT fk_post_comment_post_id 
FOREIGN KEY (post_id) REFERENCES post 
ON DELETE CASCADE;

एक बार जब आप ऐसा करते हैं, यदि आप एक postपंक्ति हटाते हैं :

DELETE FROM post WHERE id = 1

सभी संबंधित post_commentनिकाय डेटाबेस इंजन द्वारा स्वचालित रूप से हटा दिए जाते हैं। हालांकि, यह एक बहुत ही खतरनाक ऑपरेशन हो सकता है यदि आप गलती से किसी रूट इकाई को हटाते हैं।

निष्कर्ष

जेपीए cascadeऔर orphanRemovalविकल्पों का लाभ यह है कि आप खोए हुए अपडेट को रोकने के लिए आशावादी लॉकिंग से भी लाभ उठा सकते हैं ।

यदि आप JPA कैस्केडिंग तंत्र का उपयोग करते हैं, तो आपको DDL- स्तर का उपयोग करने की आवश्यकता नहीं है ON DELETE CASCADE , जो कि एक मूल इकाई को हटाने पर बहुत खतरनाक ऑपरेशन हो सकता है जिसमें कई स्तरों पर कई बाल संस्थाएँ हैं।

इस विषय के बारे में अधिक जानकारी के लिए, इस लेख को देखें


तो आपके उत्तर के अनाथ निष्कासन भाग में: पोस्ट.गेट कमैंट्स ()। रिमूव (पोस्टकामेंट); केवल Persist कैस्केड के कारण OneToMany द्विदिश मानचित्रण में काम करेगा। कैस्केडिंग के बिना और कईToOne पक्ष पर हटाने के बिना, आपके उदाहरण में, 2 संस्थाओं के बीच कनेक्शन को हटाने से डीबी में स्थायी नहीं होगा?
aurelije

अनाथ निष्कासन इससे प्रभावित नहीं होता है CascadeType। यह एक पूरक तंत्र है। अब, आप को गलत साबित करने के साथ हटा रहे हैं। अनाथ निष्कासन अपरिवर्तित संघों को हटाने के बारे में है, जबकि स्थायी नई संस्थाओं को बचाने के बारे में है। आपको इन अवधारणाओं की बेहतर समझ प्राप्त करने के लिए उत्तर में दिए गए लिंक का पालन करने की आवश्यकता है।
व्लाद मिहेल्सिया

मुझे एक बात समझ में नहीं आती है: यदि हम कभी भी एम साइड से कनेक्शन नहीं हटाते हैं, तो बिडायरेक्शनल मैपिंग में अनाथ को कैसे हटाया जाएगा? मुझे लगता है कि PostComment.post को अशक्त किए बिना पोस्ट की सूची से PostComment को हटाने से DB में उन 2 संस्थाओं के बीच कनेक्शन को हटाने का परिणाम नहीं होगा। यही कारण है कि मुझे लगता है कि अनाथ निष्कासन में कोई कमी नहीं आएगी, संबंधपरक दुनिया में पोस्टकॉम अनाथ नहीं है। कुछ खाली समय मिलने पर मैं इसका परीक्षण करूंगा।
aurelije

1
मैंने अपने हाई-परफॉर्मेंस जावा पर्सिस्टेंस GitHub रिपॉजिटरी में इन दो उदाहरणों को जोड़ा, जो यह प्रदर्शित करता है कि यह कैसे काम करता है। आपको चाइल्ड साइड को सिंक्रनाइज़ करने की आवश्यकता नहीं है क्योंकि आपको आमतौर पर सीधे संस्थाओं को हटाने के लिए करना पड़ता है। हालांकि, अनाथ हटाने केवल तभी काम करता है जब कैस्केडिंग जोड़ा जाता है, लेकिन यह एक हाइबरनेट सीमा लगता है, न कि जेपीए विनिर्देश।
व्लाद मिहालसी

5

@ गैरीके जवाब बिल्कुल शानदार है, मैंने एक घंटे orphanRemoval = trueबनाम स्पष्टीकरण की तलाश में बिताया हैCascadeType.REMOVE और इसने मुझे समझने में मदद की।

सममिंग: केवल ऑब्जेक्ट को हटाने के orphanRemoval = trueसमान कार्य करता है CascadeType.REMOVE यदि हम ऑब्जेक्ट को हटा रहे हैं (entityManager.delete(object) ) और हम चाहते हैं कि चिल्ड ऑब्जेक्ट को भी हटा दिया जाए।

जब हम कुछ डेटा लाते हैं, तो पूरी तरह से अलग-अलग साइटेशन में, List<Child> childs = object.getChilds()और फिर एक बच्चे को हटाकर ( entityManager.remove(childs.get(0)) का उपयोग करके orphanRemoval=trueउस इकाई childs.get(0)को डेटाबेस से हटा दिया जाएगा।


1
आपके दूसरे पैराग्राफ में आपको एक टाइपो है: इसमें कोई तरीका नहीं है जैसे किManManager.delete (obj); यह अस्तित्व है।
JL_SO

3

निम्नलिखित परिदृश्य में अनाथ निष्कासन का समान प्रभाव होता है: - हम कहते हैं कि हमारे पास छात्र इकाई और एक गाइड इकाई के बीच एक से कई संबंध हैं, जहाँ कई छात्रों को एक ही मार्गदर्शक और डेटाबेस में मैप किया जा सकता है। छात्र और गाइड तालिका के बीच विदेशी संबंध जैसे कि छात्र तालिका में FK के रूप में id_guide है।

    @Entity
    @Table(name = "student", catalog = "helloworld")
    public class Student implements java.io.Serializable {
     @Id
     @GeneratedValue(strategy = IDENTITY)
     @Column(name = "id")
     private Integer id;

    @ManyToOne(cascade={CascadeType.PERSIST,CascadeType.REMOVE})
    @JoinColumn(name = "id_guide")
    private Guide guide;

// मूल संस्था

    @Entity
    @Table(name = "guide", catalog = "helloworld")
    public class Guide implements java.io.Serializable {

/**
 * 
 */
private static final long serialVersionUID = 9017118664546491038L;

@Id
@GeneratedValue(strategy = IDENTITY)
@Column(name = "id", unique = true, nullable = false)
private Integer id;

@Column(name = "name", length = 45)
private String name;

@Column(name = "salary", length = 45)
private String salary;


 @OneToMany(mappedBy = "guide", orphanRemoval=true) 
 private Set<Student> students = new  HashSet<Student>(0);

इस परिदृश्य में, संबंध ऐसा है कि छात्र इकाई संबंध का स्वामी है और जैसे कि हमें संपूर्ण ऑब्जेक्ट ग्राफ को बनाए रखने के लिए छात्र इकाई को बचाने की आवश्यकता है जैसे

    Guide guide = new Guide("John", "$1500");
    Student s1 = new Student(guide, "Roy","ECE");
    Student s2 = new Student(guide, "Nick", "ECE");
    em.persist(s1);
    em.persist(s2);

यहां हम दो अलग-अलग छात्र वस्तुओं के साथ एक ही गाइड की मैपिंग कर रहे हैं और चूंकि CASCADE.PERSIST का उपयोग किया जाता है, इसलिए डेटाबेस तालिका में ऑब्जेक्ट ग्राफ नीचे दिया जाएगा (MySql in my case)

छात्र तालिका: -

ID का नाम Dept Id_Guide है

1 रॉय ईसीई 1

२ निक ईसीई १

गाइड तालिका: -

ID NAME वेतन

1 जॉन $ 1500

और अब यदि मैं छात्रों में से किसी एक का उपयोग करके हटाना चाहता हूं

      Student student1 = em.find(Student.class,1);
      em.remove(student1);

और जब एक छात्र रिकॉर्ड को हटा दिया जाता है तब संबंधित गाइड रिकॉर्ड को भी हटा दिया जाना चाहिए, जहां छात्र इकाई में CASCADE.REMOVE विशेषता चित्र में आती है और वह क्या करता है; यह छात्र को पहचानकर्ता 1 के साथ ही संबंधित गाइड ऑब्जेक्ट (पहचानकर्ता) को हटा देता है। 1)। लेकिन इस उदाहरण में, एक और छात्र वस्तु है जो एक ही गाइड रिकॉर्ड में मैप की जाती है और जब तक हम गाइड एंटिटी में orphanRemoval = true विशेषता का उपयोग नहीं करते हैं, तब तक ऊपर हटाए गए कोड काम नहीं करेंगे।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.