2011-07-11 19 views
16

प्रश्न शीर्षक मूल रूप से यह सब कहता है। क्या यह जेपीए/हाइबरनेट में में डेटाबेस से किसी इकाई को हटाने से रोकता है? मैं चाहता हूं कि इकाई को वास्तव में इसे हटाने के बजाय इकाई को "छुपा" के रूप में फ़्लैग करना है।जेपीए/हाइबरनेट - प्रीरमोव हैंडलर में हटाने को रोकें?

मैं भी Cascade सेमेन्टिक्स संरक्षित करना चाहता हूं, जैसे कि यदि मैं किसी अन्य इकाई के संग्रह के स्वामित्व वाली इकाई को हटाने का प्रयास करता हूं, तो स्वामित्व वाली इकाई और उसके संग्रह में प्रत्येक इकाई को बिना किसी अतिरिक्त काम के छुपाया जाता है @PreRemove हैंडलर को लागू करने से परे, मेरे हिस्से पर जरूरी है जो हटाने को रोकता है और इकाई को छिपा हुआ चिह्नित करता है।

क्या यह संभव है, या मुझे कुछ अन्य दृष्टिकोण जानने की आवश्यकता है?

+0

क्या आप जेपीए का उपयोग करके लॉजिकल डिलीशन की नकल करने का प्रयास कर रहे हैं? –

+0

@ विनीत रेनॉल्ड्स - संक्षेप में, हां। मैं चाहता हूं कि रिकॉर्ड चारों ओर रखें क्योंकि ऐप मोबाइल क्लाइंट के साथ समन्वयित करता है, और इसे हटाए जाने वाले ग्राहकों को बताने में सक्षम होना चाहिए। मैं उस समय के साथ-साथ हटाए गए टाइमस्टैम्प के साथ-साथ अलग-अलग तालिका में हटाई गई सभी चीज़ों की आईडी रखकर इस पर काम कर सकता हूं, लेकिन मैं केवल विलोपन व्यवहार को ओवरराइड करने में सक्षम होना पसंद करूंगा ताकि यह सिर्फ उन्हें हटाने के बजाय चीजों को छुपाता है। – aroth

उत्तर

12

क्या जेपीए/हाइबरनेट में डेटाबेस से किसी इकाई को हटाने से सावधानीपूर्वक रोकना संभव है?

हां, जब तक आप EntityManager.remove(entity) का उपयोग करने से बचें, यह संभव है। यदि आप EntityManager.remove() का उपयोग करते हैं, तो जेपीए प्रदाता ऑब्जेक्ट को एक संबंधित SQL DELETE कथन का उपयोग करके हटाने के लिए ध्वजांकित करेगा जिसका अर्थ है कि ऑब्जेक्ट को हटाने के लिए ऑब्जेक्ट को ध्वजांकित करने के बाद एक सुरुचिपूर्ण समाधान संभव नहीं होगा।

हाइबरनेट में, आप इसे @SQLDelete and @Where annotations का उपयोग करके प्राप्त कर सकते हैं। हालांकि, यह जेपीए के साथ अच्छी तरह से खेल नहीं पाएगा, क्योंकि EntityManager.find()@Where एनोटेशन में निर्दिष्ट फ़िल्टर को अनदेखा करने के लिए जाना जाता है।

इसलिए एक जेपीए-एकमात्र समाधान "जीवित" इकाइयों से डेटाबेस में तार्किक रूप से हटाए गए इकाइयों को अलग करने के लिए इकाई वर्गों में एक ध्वज यानी एक कॉलम जोड़ना शामिल होगा। यह सुनिश्चित करने के लिए कि तर्कसंगत हटाए गए इकाइयां परिणाम सेट में उपलब्ध नहीं होंगी, आपको उचित प्रश्न (जेपीक्यूएल और मूल) का उपयोग करने की आवश्यकता होगी। आप @PreUpdate और @PrePersist एनोटेशन का उपयोग इकाई जीवन चक्र घटनाओं पर हुक करने के लिए कर सकते हैं ताकि यह सुनिश्चित किया जा सके कि ध्वज जारी रहता है और घटनाओं को अद्यतन करता है। दोबारा, आपको यह सुनिश्चित करने की आवश्यकता होगी कि आप EntityManager.remove विधि का आह्वान नहीं करेंगे।

मैं जीवन चक्र घटना है कि संस्थाओं को हटाने के लिए शुरू हो रहा है पर हुक करने @PreRemove एनोटेशन का उपयोग कर सुझाव दिया होता, लेकिन एक इकाई श्रोता का उपयोग कर हटाए जाने को रोकने के लिए नीचे वर्णित कारणों के लिए मुसीबत से भरा है:

  • यदि आपको SQL DELETE को लॉजिकल अर्थ में होने से रोकने की आवश्यकता है, तो आपको * को फिर से बनाने के लिए उसी लेनदेन में ऑब्जेक्ट को जारी रखना होगा। एकमात्र समस्या यह है कि यह एंटीलिस्टनर में EntityManager को संदर्भित करने का एक अच्छा डिज़ाइन निर्णय नहीं है, और अनुमान के अनुसार श्रोता में EntityManager.persist का आह्वान करें। तर्क काफी सरल है - EntityListener में एक अलग EntityManager संदर्भ प्राप्त करने के अंत में समाप्त हो जाएगा और इससे केवल आपके आवेदन में अस्पष्ट और भ्रमित व्यवहार होगा।
  • यदि आपको लेनदेन में SQL DELETE को होने से रोकने की आवश्यकता है, तो आपको अपने EntityListener में अपवाद फेंकना होगा। यह आम तौर पर लेनदेन को वापस ले जाता है (विशेष रूप से यदि अपवाद एक रनटाइम अपवाद है या एक एप्लिकेशन अपवाद है जिसे रोलबैक का कारण बनता है) घोषित किया जाता है, और कोई लाभ नहीं देता है, क्योंकि पूरे लेनदेन को वापस ले जाया जाएगा।

आप हाइबरनेट के बजाय EclipseLink उपयोग करने का विकल्प है, तो ऐसा लगता है कि एक सुरुचिपूर्ण समाधान संभव है यदि आप एक उपयुक्त DescriptorCustomizer परिभाषित या AdditionalCriteria एनोटेशन का उपयोग करके। ये दोनों EntityManager.remove और EntityManager.find आमंत्रण के साथ अच्छी तरह से काम करने लगते हैं। हालांकि, आपको अभी भी तार्किक रूप से हटाए गए इकाइयों के लिए अपने जेपीक्यूएल या मूल प्रश्नों को लिखने की आवश्यकता हो सकती है।


* यह JPA Wikibook on the topic of cascading Persist में उल्लिखित है:

अगर आप इसे नष्ट कर दिया है करने के लिए यदि आप तो कहते हैं वस्तु पर जारी रहती है एक वस्तु निकालते हैं तो वह वस्तु को फिर से शुरू होगी, और यह फिर से लगातार बन जाएगा। यह वांछित हो सकता है अगर यह जानबूझकर है, लेकिन जेपीए स्पेक को कैस्केड के लिए इस व्यवहार की भी आवश्यकता होती है। तो यदि आप किसी ऑब्जेक्ट को हटाते हैं, लेकिन एक कैस्केड रिश्ते संबंध से इसका संदर्भ निकालना भूल जाते हैं, तो हटा दिया जाएगा।

+0

आह, मैं 'EntityManager.remove()' का उपयोग करके इसे काम करने में सक्षम होने की उम्मीद कर रहा था। लेकिन जैसा कि आप कहते हैं, श्रोता में उचित 'EntityManager' उदाहरण प्राप्त करने का कोई विश्वसनीय तरीका नहीं है। जैसा कि आपने सुझाव दिया है और अपडेट के साथ अपने हटाए गए स्थान को बदल दिया है और यह काम कर रहा है, मैं लंबा सफर तय कर चुका हूं। मेरी इच्छा है कि जेपीए ने इस उपयोग-मामले के लिए एक और अधिक सुरुचिपूर्ण समाधान की अनुमति दी है। – aroth

+0

हां, मैं इस बात से सहमत हूं कि जेपीए में एक और सुरुचिपूर्ण समाधान शामिल किया जाना चाहिए ताकि 'em.remove()' को मूल एसक्यूएल क्वेरी या जेपीक्यूएल कथन में मैप किया जा सके, इस कस्टम व्यवहार को उचित स्थान पर निर्दिष्ट किया जा रहा है - इकाई, या कहीं और पर। –

संबंधित मुद्दे