2011-11-27 13 views
8

मैं एक जनक एक ManyToOne रिश्ते में एक बाल इकाई के साथ इकाई है:जेपीए कैस्केड के साथ डुप्लिकेट से कैसे बचें?

@Entity class Parent { 
    // ... 
    @ManyToOne((cascade = {CascadeType.ALL}) 
    private Child child; 
    // ... 
} 

बाल एक अद्वितीय क्षेत्र है:

@Entity class Child { 
    // ... 
    @Column(unique = true) 
    private String name; 
    // ... 
} 

जब मैं किसी नए की जरूरत है चाइल्ड, मैं चाइल्डडाओ फ़िर पूछता हूं सेंट:

Child child = childDao.findByName(name); 
if(child == null) { 
    child = new Child(name); 
} 

Parent parent = new Parent(); 
parent.setChild(child); 

समस्या यह है, अगर मैं ऊपर दो बार (बाल के लिए एक ही नाम के साथ) की तरह करते हैं, और केवल अंत में जनक जारी रहती है, मैं एक बाधा अपवाद मिलता है। जो सामान्य लगता है, क्योंकि शुरुआत में निर्दिष्ट नाम के साथ डेटाबेस में कोई बच्चा नहीं था।

समस्या यह है कि, मुझे यकीन नहीं है कि इस स्थिति से बचने का सबसे अच्छा तरीका क्या होगा।

+2

क्या आप वाकई अपना मॉडल ठीक है? बच्चे के कई माता-पिता हो सकते हैं, और माता-पिता के पास केवल एक बच्चा हो सकता है? –

+0

मेरा उत्तर एक वनू रिश्ते को मानता है - उपर्युक्त टिप्पणी बिल्कुल सही है, यह सही है अगर यह एक विचित्र नाम है। –

+0

हां, मॉडल सही है। मैंने उदाहरण के लिए इकाइयों का नाम बदल दिया, और ऐसा लगता है कि मैं बेहतर कर सकता था। – Cos64

उत्तर

9

आप बच्चे के दो गैर-लगातार उदाहरण new Child() के साथ दो बार बना रहे हैं और इन्हें दो अलग-अलग माता-पिता में डाल रहे हैं। जब आप अभिभावक वस्तुओं को जारी रखते हैं, तो दो नए बाल उदाहरणों में से प्रत्येक को कैस्केड के माध्यम से रखा/डाला जाएगा, प्रत्येक एक अलग @Id के साथ। नाम पर अद्वितीय बाधा तोड़ जाती है। यदि आप CascadeType.ALL कर रहे हैं, तो हर बार जब आप new Child() करते हैं तो आपको एक अलग निरंतर ऑब्जेक्ट मिल रहा है।

यदि आप वास्तव में दो बच्चों के उदाहरणों को एक ही आईडी के साथ एक लगातार वस्तु के रूप में माना जाना चाहते हैं, तो आपको दृढ़ता संदर्भ/सत्र से संबद्ध होने के लिए इसे अलग से जारी रखना होगा। childDao.findByName पर आने वाली कॉल तब सम्मिलित हो जाएंगी और आपके द्वारा बनाए गए नए बच्चे को वापस कर देंगी, इसलिए आप new Child() दो बार नहीं कर पाएंगे।

1

आप बच्चे के ऑब्जेक्ट को सेट कर रहे हैं, यदि माता-पिता को जारी रखें तो आप डेटाबेस में एक रजिस्टर संग्रहीत कर रहे हैं जो एक मौजूदा बच्चे को इंगित करता है।

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

पहले बच्चे की वस्तु को जारी रखने या विलय करने का प्रयास करें।

+0

अभिभावक के बच्चे के क्षेत्र में 'कैस्केड टाइप टाइप' सेट है। कोई स्पष्ट विलय की आवश्यकता नहीं है। –

6

आपको यह मिल रहा है क्योंकि आप किसी ऑब्जेक्ट को जारी रखने का प्रयास कर रहे हैं जो पहले से मौजूद है (उसी आईडी)। आपका कैस्केड शायद जारी नहीं है यह मेर्ज/अपडेट/रिमूव/डिटेच है। इस स्थिति से बचने का सबसे अच्छा तरीका कैस्केड को ठीक तरह से स्थापित किया गया है या मैन्युअल रूप से कैस्केड का प्रबंधन करता है। मूल रूप से बोलते हुए, कैस्केडिंग लगातार सामान्य अपराधी है।

आप संभावित कुछ इस तरह हैं:

//SomeService--I assume you create ID's on persist 
saveChild(Parent parent, Child child) 
{ 
    //Adding manually (using your cascade ALL) 
    if(child.getId() == null) //I don't exist persist 
    persistence.persist(child); 
    else 
    persistence.merge(child); //I'm already in the DB, don't recreate me 

    parent.setChild(child); 
    saveParent(parent); //using a similar "don't duplicate me" approach. 
} 

cascades हो सकता है अत्यंत निराशा होती अगर तुम ढांचे संभाल क्योंकि आप कभी-कभी अपडेट छोड़ें देंगे अगर यह (कैशिंग विशेष रूप से ManyToOne में संग्रह के साथ है रिश्तों)। यदि आप स्पष्ट रूप से माता-पिता को सहेजते नहीं हैं और ढांचे को कैस्केड से निपटने की अनुमति देते हैं। आम तौर पर मैं अपने माता-पिता से रिश्ते में एक कैस्केड.एएलएल को अनुमति देता हूं और अपने बच्चों से हटा/व्यक्तिगत द्वारा सभी का एक कैस्केड देता हूं। मैं एक एक्लीपसेलिंक उपयोगकर्ता हूं इसलिए हाइबरनेट/अन्य के साथ मेरा अनुभव सीमित है और मैं कैशिंग से बात नहीं कर सकता। * वास्तव में, इसके बारे में सोचें - अगर आप बच्चे को बचा रहे हैं तो क्या आप वास्तव में उससे संबंधित सभी वस्तुओं को सहेजना चाहते हैं? इसके अलावा, अगर आप बच्चे को जोड़ रहे हैं, तो क्या आपको माता-पिता को सूचित नहीं करना चाहिए? *

आपके मामले में मेरे पास बस मेरे दाओ/सेवा में "सेवेंटेंट" और "सेव चिल्ड" विधि होगी जो सुनिश्चित करता है कि कैश सही है और सिरदर्द से बचने के लिए डेटाबेस सही है। मैन्युअल रूप से प्रबंधन का मतलब है कि आपके पास पूर्ण नियंत्रण होगा और आपको अपने गंदे काम करने के लिए कैस्केड पर भरोसा नहीं करना पड़ेगा। एक ही दिशा में वे शानदार हैं, जिस समय वे "अपस्ट्रीम" आते हैं, आपको कुछ अप्रत्याशित व्यवहार होने जा रहे हैं।

3

यदि आप दो ऑब्जेक्ट्स बनाते हैं, और जेपीए को स्वचालित रूप से जारी रखने दें, तो आपको डेटाबेस में दो पंक्तियां मिलेंगी। तो, आपके पास दो विकल्प हैं: दो ऑब्जेक्ट्स न बनाएं, या जेपीए को स्वचालित रूप से जारी न करें।

दो ऑब्जेक्ट्स बनाने से बचने के लिए, आपको अपना कोड व्यवस्थित करना होगा ताकि दो माता-पिता एक ही नाम वाले बच्चों को बनाने का प्रयास करें, तो उन्हें वही वास्तविक उदाहरण मिलेगा। आप शायद WeakHashMap (स्थानीय अनुरोध द्वारा संदर्भित वर्तमान अनुरोध के लिए स्कॉप्ड) चाहते हैं, नाम से कुंजीपटल, जहां माता-पिता अपने नए बच्चे के नाम को देख सकते हैं यह देखने के लिए कि क्या बच्चा पहले से मौजूद है या नहीं। यदि नहीं, तो वे ऑब्जेक्ट बना सकते हैं और इसे मानचित्र में डाल सकते हैं।

जेपीए स्वचालित रूप से ऑब्जेक्ट्स को बनाए रखने से बचने के लिए, कैस्केड को छोड़ दें और सृजन के तुरंत बाद संदर्भ में ऑब्जेक्ट्स मैन्युअल रूप से जोड़ने के लिए persist का उपयोग करें।

चूंकि एक दृढ़ता संदर्भ मूल रूप से एक धोखाधड़ी वाले वीक हैशैप डेटाबेस से जुड़ा हुआ है, तो ये दृष्टिकोण बहुत कम होते हैं जब यह नीचे आता है।

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