2009-09-30 12 views
6

यह एक छोटा सा प्रयोग मैंने किया है:लिंक कैशिंग डेटा मान - प्रमुख समरूपता समस्या?

MyClass obj = dataContext.GetTable<MyClass>().Where(x => x.ID = 1).Single(); 
Console.WriteLine(obj.MyProperty); // output = "initial" 
Console.WriteLine("Waiting..."); // put a breakpoint after this line 
obj = null; 
obj = dataContext.GetTable<MyClass>().Where(x => x.ID = 1).Single(); // same as before, but reloaded 
Console.WriteLine(obj.MyProperty); // output still = "initial" 
obj.MyOtherProperty = "foo"; 
dataContext.SubmitChanges(); // throws concurrency exception 

जब मैं लाइन 3 के बाद ब्रेकप्वाइंट मारा, मैं एक SQL क्वेरी विंडो पर जाएं और मैन्युअल रूप से मान "अद्यतन" में बदलें। तब मैं दौड़ता रहता हूं। लिंक मेरी ऑब्जेक्ट को फिर से लोड नहीं करता है, लेकिन उसमें पहले से स्मृति का उपयोग करता है! डेटा समेकन के लिए यह विशाल समस्या है!

आप ऑब्जेक्ट्स के इस छिपे हुए कैश को कैसे अक्षम करते हैं जो लिंक्स स्पष्ट रूप से स्मृति में रख रहा है?

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

उत्तर

5

यह एक मुद्दा मैं पहले का सामना करना पड़ा नहीं है (के बाद से मैं DataContexts समय की लंबी अवधि के लिए खुला रखने के लिए करते हैं नहीं है), लेकिन यह किसी और की तरह लग रहा है:

http://www.rocksthoughts.com/blog/archive/2008/01/14/linq-to-sql-caching-gotcha.aspx

+1

+1 ओएमजी, यह वास्तव में एक गोटो है! उसे सी # गोटाचा केबी में जोड़ना होगा ... –

+1

इससे भी बदतर, अगर आप वहां उसकी सलाह का पालन करते हैं और ऑब्जेक्टट्रैकिंग सक्षम = झूठा सेट करते हैं, तो आप केवल डीबी से पढ़ सकते हैं; आप सबमिट चेंज नहीं कर सकते! यह वास्तव में जीवन को मुश्किल बनाता है! –

+0

यहां सी # गॉचा केबी का एक लिंक है: http://stackoverflow.com/questions/241134/what-is-the-worst-c-net-gotcha –

2

DataContext की ऑब्जेक्टट्रैकिंग सक्षम संपत्ति को गलत पर सेट करें।

जब ऑब्जेक्टट्रैकिंग सक्षम सत्य पर सेट किया गया है तो डेटाकॉन्टेक्स्ट Unit of Work जैसा व्यवहार कर रहा है। यह किसी ऑब्जेक्ट को मेमोरी में लोड करने जा रहा है ताकि वह इसमें बदलावों को ट्रैक कर सके। DataContext को ऑब्जेक्ट को याद रखना होगा क्योंकि मूल रूप से यह पता लगाने के लिए कि क्या कोई परिवर्तन किया गया है या नहीं।

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

यदि आप केवल पढ़ने के परिदृश्य में काम नहीं कर रहे हैं तो मुझे यकीन नहीं है कि आप इसे इस तरह से क्यों काम करना चाहते हैं। यदि आपने संपादन किए हैं तो आप डेटाबेस से संशोधित स्थिति में क्यों खींचेंगे?

+0

हां, लेकिन मैं केवल पढ़ने के लिए वातावरण में काम नहीं कर रहा हूं। कोई अन्य विचार? –

+0

यह डिज़ाइन द्वारा है। यह आपके लिए ऑप्टिकल कॉन्सुरेंसी का उपयोग करके राज्य, संशोधित और लिखने के लिए तैयार किया गया है। आप DataContext पर रीफ्रेश कॉल कर सकते हैं लेकिन इससे आपके द्वारा किए गए किसी भी बदलाव को मार सकता है। यह वास्तविक समय सिंकिंग प्रदान करने के लिए नहीं है। वास्तविक समय समन्वयन और संपादन अच्छी तरह से एक साथ नहीं जाते हैं। –

1

LINQ से SQL पहचान पहचान डिज़ाइन पैटर्न का उपयोग करता है जिसका अर्थ है कि यह हमेशा किसी भी ऑब्जेक्ट की प्राथमिक कुंजी के लिए उसी ऑब्जेक्ट को वापस कर देगा (जब तक आप ऑब्जेक्ट ट्रैकिंग बंद नहीं करते)।

समाधान या तो दूसरा डेटा संदर्भ का उपयोग करता है यदि आप नहीं चाहते हैं कि यह पहले उदाहरण में हस्तक्षेप करे या यदि आप ऐसा करते हैं तो पहले उदाहरण को रीफ्रेश करें।

5

लिंककॉटस्क्ल में समवर्ती समस्याओं से निपटने के लिए विभिन्न प्रकार के टूल्स हैं।

हालांकि, पहला कदम यह स्वीकार करना है कि हल करने के लिए एक सहमति समस्या है!

सबसे पहले, डेटाकॉन्टेक्स्ट की इच्छित वस्तु जीवन चक्र को यूनिटऑफवर्क से मेल खाना चाहिए। यदि आप विस्तारित अवधि के लिए एक पर हो रहे हैं, तो आपको इतना कठिन काम करना होगा क्योंकि कक्षा को इस तरह इस्तेमाल करने के लिए डिज़ाइन नहीं किया गया है।

दूसरा, डेटाकॉन्टेक्स्ट प्रत्येक ऑब्जेक्ट की दो प्रतियां ट्रैक करता है। एक मूल स्थिति है और एक बदले/परिवर्तनीय राज्य है। यदि आप आईडी = 1 के साथ MyClass के लिए पूछते हैं, तो यह आपको उसी उदाहरण पर वापस देगा, यह आपको पिछली बार दिया गया है, जो बदला/परिवर्तनीय संस्करण है ... मूल नहीं।यह स्मृति उदाहरणों में समवर्ती समस्याओं को रोकने के लिए ऐसा करना चाहिए ... LinqToSql एक DataContext को MyClass (Id = 1) के दो परिवर्तनीय संस्करणों से अवगत होने की अनुमति नहीं देता है।

तीसरा, डेटाकॉन्टेक्स्ट को पता नहीं है कि आपका इन-मेमोरी परिवर्तन डेटाबेस परिवर्तन से पहले या बाद में आता है, और इसलिए कुछ मार्गदर्शन के बिना समवर्ती संघर्ष को रेफरी नहीं कर सकता है। यह सब देखता है:

  • मैंने डेटाबेस से MyClass (Id = 1) पढ़ा है।
  • प्रोग्रामर संशोधित MyClass (आईडी = 1)।
  • मैं MyClass (आईडी = 1) भेजा वापस डेटाबेस के लिए
    • डेटाबेस के संस्करण मूल (आशावादी संगामिति) से मेल खाता है, तो अद्यतन सफल होगा (जहां खंड में आशावादी संगामिति देखने के लिए इस एसक्यूएल को देखो)।
    • यदि डेटाबेस का संस्करण मूल से मेल नहीं खाता है तो अद्यतन समवर्ती अपवाद के साथ विफल हो जाएगा।

ठीक है, अब है कि समस्या कहा गया है, यहाँ तरीके से निपटने के लिए की एक जोड़ी है।

आप डेटाकॉन्टेक्स्ट को फेंक सकते हैं और शुरू कर सकते हैं। यह कुछ के लिए थोड़ा भारी हाथ है, लेकिन कम से कम इसे लागू करना आसान है।

आप मूल उदाहरण या बदले/परिवर्तनीय उदाहरण के लिए DataContext.Refresh(RefreshMode, target) (reference docs with many good concurrency links in the "Remarks" section) पर कॉल करके डेटाबेस मान के साथ रीफ्रेश किए जाने के लिए कह सकते हैं। यह ग्राहक पक्ष को बदल देगा और आपके कोड को काम करने की अनुमति देगा कि अंतिम परिणाम क्या होना चाहिए।

आप डीबीएमएल (ColumnAttribute.UpdateCheck) में समवर्ती जांच को बंद कर सकते हैं। यह आशावादी समेकन को अक्षम करता है और आपका कोड किसी और के परिवर्तनों पर फंस जाएगा। इसके अलावा भारी हाथ भी लागू करना आसान है।

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