2010-07-16 16 views
28

एंटिटी फ्रेमवर्क में नया होने के नाते, मैं वास्तव में मुद्दों के इस सेट के साथ आगे बढ़ने के तरीके पर अटक गया हूं। प्रोजेक्ट पर मैं वर्तमान में काम कर रहा हूं, पूरी साइट ईएफ मॉडल के साथ काफी एकीकृत है। सबसे पहले, ईएफ संदर्भ तक पहुंच को निर्भरता इंजेक्शन बूटस्ट्रैपर का उपयोग करके नियंत्रित किया जा रहा था। परिचालन कारणों से हम एक डीआई पुस्तकालय का उपयोग करने में सक्षम नहीं थे। मैंने इसे हटा दिया और जहां आवश्यक हो वहां संदर्भ ऑब्जेक्ट के अलग-अलग उदाहरणों का एक मॉडल इस्तेमाल किया। मुझे निम्नलिखित अपवाद मिलना शुरू हो गया:.NET इकाई फ्रेमवर्क और लेनदेन

प्रकार 'XXX' को एक से अधिक बार मैप किया गया है।

हम इस निष्कर्ष पर पहुंचे कि संदर्भ के विभिन्न उदाहरण इस मुद्दे का कारण बन रहे थे। इसके बाद मैंने संदर्भ ऑब्जेक्ट को एक स्थिर आवृत्ति में सारणीबद्ध किया जिसे प्रत्येक थ्रेड/पेज द्वारा एक्सेस किया जा रहा था। मैं अब लेन-देन के बारे में कई अपवादों में से एक हो रही है:

नई लेन-देन की अनुमति नहीं है क्योंकि वहाँ अन्य थ्रेड सत्र में चल रहे हैं।

लेनदेन ऑपरेशन नहीं किया जा सकता क्योंकि इस लेनदेन पर काम कर रहे लंबित अनुरोध हैं।

ExecuteReader को आदेश देने के लिए कमांड की आवश्यकता होती है जब कमांड को असाइन किया गया कनेक्शन लंबित स्थानीय लेनदेन में होता है। कमांड की लेनदेन संपत्ति शुरू नहीं की गई है।

इनमें से आखिरी अपवाद लोड ऑपरेशन पर हुआ। मैं संदर्भ स्थिति को वापस असफल थ्रेड पर डीबी पर सहेजने की कोशिश नहीं कर रहा था। हालांकि एक और धागा ऐसा ऑपरेशन कर रहा था।

ये अपवाद सर्वोत्तम रूप से अस्थायी हैं, लेकिन मैंने साइट को ऐसे राज्य में जाने में कामयाब रहा है जहां लेनदेन लॉक के कारण नए कनेक्शन अस्वीकार कर दिए गए थे। दुर्भाग्य से मुझे अपवाद विवरण नहीं मिल रहा है।

मुझे लगता है कि मेरा पहला सवाल है, क्या ईएफ मॉडल को एक स्थिर एकल उदाहरण से उपयोग किया जाना चाहिए? साथ ही, क्या ईएफ में लेनदेन की आवश्यकता को दूर करना संभव है? मैं सफलता के बिना एक TransactionScope वस्तु का उपयोग कर की कोशिश की है ...

ईमानदार मैं एक बहुत यहाँ अटक कर रहा हूँ होने के लिए, और नहीं समझ सकता क्यों (क्या होना चाहिए) काफी सरल संचालन इस तरह के एक समस्या पैदा कर रहे हैं ...

+0

संबंधित: http://stackoverflow.com/questions/10585478/one-dbcontext-per-web-request- क्यों – Steven

+0

यह बहुत बुरा है कि आप एक आईओसी बूटस्ट्रैपर का उपयोग नहीं कर सकते, क्योंकि [Ninject] (http के साथ समाधान : //www.ninject.org/) _request scope_ पर "सामान्य" उदाहरण को बाध्य करना होगा, जैसा कि अन्य ने सुझाव दिया है: 'kernel.ind >()। > () .रूक्वेस्टस्कोप(); '- महत्वपूर्ण हिस्सा ** 'InRequestScope' ** – drzaus

उत्तर

50

एक वेब अनुप्रयोग में वैश्विक ObjectContext बनाना बहुत खराब है। ObjectContext कक्षा थ्रेड-सुरक्षित नहीं है। यह unit of work की अवधारणा के आसपास बनाया गया है और इसका मतलब है कि आप इसे एक एकल उपयोग केस संचालित करने के लिए उपयोग करते हैं: इस प्रकार एक व्यापार लेनदेन के लिए। यह एक एकल अनुरोध को संभालने के लिए है।

आपको जो अपवाद मिलता है, क्योंकि प्रत्येक अनुरोध के लिए आप एक नया लेनदेन बनाते हैं, लेकिन उसी ObjectContext का उपयोग करने का प्रयास करें। आप भाग्यशाली हैं कि ObjectContext इसका पता लगाता है और अपवाद फेंकता है, क्योंकि अब आप पाएंगे कि यह काम नहीं करेगा।

कृपया इस बारे में सोचें कि यह क्यों काम नहीं कर सकता है। ObjectContext में आपके डेटाबेस में इकाइयों का एक स्थानीय कैश है। यह आपको परिवर्तनों का एक समूह बनाने और अंततः डेटाबेस में उन परिवर्तनों को सबमिट करने की अनुमति देता है। एक ही स्थिर ObjectContext का उपयोग करते समय, उस ऑब्जेक्ट पर SaveChanges पर कॉल करने वाले एकाधिक उपयोगकर्ताओं के साथ, यह कैसे पता होना चाहिए कि वास्तव में क्या किया जाना चाहिए और क्या नहीं होना चाहिए?क्योंकि यह नहीं जानता है, यह सभी परिवर्तनों को बचाएगा, लेकिन उस समय एक और उपयोगकर्ता अभी भी बदलाव कर रहा है। जब आप भाग्यशाली होते हैं तो ईएफ या आपका डेटाबेस विफल हो जाएगा, क्योंकि संस्थाएं अमान्य स्थिति में हैं। यदि आप दुर्भाग्यपूर्ण ऑब्जेक्ट्स हैं जो अमान्य स्थिति में हैं, तो सफलतापूर्वक डेटाबेस में सहेजे जाते हैं और आपको सप्ताह बाद पता चल सकता है कि आपका डेटाबेस बकवास से भरा है। आपकी समस्या का समाधान create at least one ObjectContext per request है। सिद्धांत रूप में आप उपयोगकर्ता सत्र में किसी ऑब्जेक्ट संदर्भ को कैश कर सकते हैं, यह भी एक बुरा विचार है, क्योंकि ObjectContext आमतौर पर बहुत लंबा रहता है और इसमें स्थिर डेटा होगा (क्योंकि इसका आंतरिक कैश स्वचालित रूप से रीफ्रेश नहीं होगा)।

अद्यतन:

भी ध्यान रखें कि धागा प्रति एक ObjectContext होने पूरा वेब अनुप्रयोग के लिए एक एक उदाहरण के रूप में होने के रूप में बुरा है। एएसपी.नेट एक थ्रेड पूल का उपयोग करता है जिसका अर्थ है कि एक वेब अनुप्रयोग के जीवनकाल के दौरान सीमित मात्रा में धागे बनाए जाएंगे। इसका मूल रूप से मतलब है कि उन ObjectContext उदाहरण उस मामले में अभी भी आवेदन के जीवनकाल के लिए जीते हैं, जिससे डेटा की स्थिरता के साथ समान समस्याएं होती हैं।

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

+1

ठीक है, वास्तव में यही मैंने सोचा था कि मैं कर रहा था ... मैं सामान्य रूप से स्थिर डेटा संदर्भ ऑब्जेक्ट्स का उपयोग नहीं करता, लेकिन वह बेताब हो रहा था। बाहर निकलता है मेरे पास ए एन अन्य बग था जहां मेरे पास संदर्भ के एक उदाहरण थे।हालांकि वे एक स्थिर वस्तु के अंदर थे, जो ऐसा कारण प्रतीत होता है। मेरे जीवन के 2 घंटे वापस नहीं आ रहे हैं ... धन्यवाद – sicknote

+19

केवल दो घंटे? फिर आप एक भाग्यशाली आदमी हैं :-) – Steven

+1

और इस तरह की समस्याओं का सामना करने का सबसे अच्छा विकल्प क्या है? – Romias

4

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

एक एकल स्थैतिक संदर्भ उदाहरण काम नहीं करेगा, लेकिन प्रति थ्रेड के कई संदर्भ उदाहरण परेशानी होगी साथ ही आप संदर्भों को मिश्रण और मिलान नहीं कर सकते हैं। आपको प्रति थ्रेड का एक संदर्भ चाहिए। हमने निर्भरता इंजेक्शन प्रकार पैटर्न का उपयोग करके हमारे आवेदन में यह किया है।

using (TransactionScope ts = new TransactionScope()) 
{ 
    using (ObjectContext oContext = new ObjectContext("MyConnection")) 
    { 
     oBLLClass.Update(oEntity, oContext); 
    } 
} 

आप अपने अद्यतन के भीतर अन्य BLL/DAL तरीकों कॉल करने के लिए की जरूरत है (या जो भी विधि आपके द्वारा चुने गए: हमारे BLL और दाल वर्गों के तरीकों में एक पैरामीटर के रूप में एक संदर्भ, इस तरह आप नीचे की तरह कुछ कर सकते हैं लेने के) आप बस एक ही संदर्भ पास पास करते हैं। इस तरह अद्यतन/आवेषण/हटाए गए परमाणु हैं, एक विधि के भीतर eveything एक ही संदर्भ उदाहरण का उपयोग कर रहा है, लेकिन उस उदाहरण का उपयोग अन्य धागे द्वारा नहीं किया जा रहा है।

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