2010-12-09 7 views
20

अद्यतन (2010-12-21): परीक्षणों के आधार पर इस प्रश्न को पूरी तरह से पुनर्लेखित करें जो मैं कर रहा हूं। इसके अलावा, यह एक पीओसीओ विशिष्ट प्रश्न होता था, लेकिन यह पता चला कि मेरा प्रश्न अनिवार्य रूप से POCO विशिष्ट नहीं है।आशावादी कॉनकुरेंसी अपवाद कुछ स्थितियों में इकाई फ्रेमवर्क में काम नहीं करता है

मैं इकाई फ्रेमवर्क का उपयोग कर रहा हूं और मुझे अपने डेटाबेस तालिका में टाइमस्टैम्प कॉलम मिला है जिसका उपयोग आशावादी समेकन के लिए परिवर्तनों को ट्रैक करने के लिए किया जाना चाहिए। मैंने एंटिटी डिज़ाइनर में "फिक्स्ड" में इस संपत्ति के लिए समवर्ती मोड सेट किया है और मुझे असंगत परिणाम मिल रहे हैं। यहां कुछ सरल परिदृश्य हैं जो दर्शाते हैं कि समेकन जांच एक परिदृश्य में काम करती है लेकिन दूसरे में नहीं।

सफलतापूर्वक OptimisticConcurrencyException फेंकता है:

अगर मैं एक कट इकाई देते हैं, तो SaveChanges एक OptimisticConcurrencyException फेंक होगा अगर वहाँ एक टाइमस्टैम्प संघर्ष है:

[HttpPost] 
    public ActionResult Index(Person person) { 
     _context.People.Attach(person); 
     var state = _context.ObjectStateManager.GetObjectStateEntry(person); 
     state.ChangeState(System.Data.EntityState.Modified); 
     _context.SaveChanges(); 
     return RedirectToAction("Index"); 
    } 

फेंक नहीं है OptimisticConcurrencyException:

दूसरी ओर, अगर मैं अपनी इकाई की एक नई प्रति डी से पुनर्प्राप्त करता हूं

[HttpPost] 
    public ActionResult Index(Person person) { 
     var currentPerson = _context.People.Where(x => x.Id == person.Id).First(); 
     currentPerson.Name = person.Name; 

     // currentPerson.VerColm == [0,0,0,0,0,0,15,167] 
     // person.VerColm == [0,0,0,0,0,0,15,166] 
     currentPerson.VerColm = person.VerColm; 

     // in POCO, currentPerson.VerColm == [0,0,0,0,0,0,15,166] 
     // in non-POCO, currentPerson.VerColm doesn't change and is still [0,0,0,0,0,0,15,167] 
     _context.SaveChanges(); 
     return RedirectToAction("Index"); 
    } 

एसक्यूएल प्रोफाइलर के आधार पर यह दिखाई देता है: atabase और मैं कुछ क्षेत्रों पर एक आंशिक अद्यतन करते हैं, और उसके बाद SaveChanges() कहते हैं, तो भले ही एक टाइमस्टैम्प द्वंद्व हो, मैं नहीं एक OptimisticConcurrencyException मिलता है इकाई फ्रेमवर्क नए VerColm (जो टाइमस्टैम्प संपत्ति है) को अनदेखा कर रहा है और इसके बजाय मूल रूप से लोड वर्कॉल का उपयोग कर रहा है। इस वजह से, यह कभी भी आशावादी कॉनकुरेंसी अपवाद नहीं फेंक देगा।


अद्यतन:

ध्यान दें कि मैं भी मैं क्या मेरे नियंत्रक कार्रवाई में देखने के इस उदाहरण के माध्यम से काम करते हुए के साथ मेल खाना उपरोक्त कोड पर टिप्पणियां जोड़ीं: जनवरी के अनुरोध के अनुसार अतिरिक्त जानकारी जोड़ना।

यह अद्यतन करने से पहले मेरी डेटाबेस में VerColm का मान: 0x0000000000000FA7

यहाँ एसक्यूएल प्रोफाइलर जब अद्यतन कर से पता चलता है:

exec sp_executesql N'update [dbo].[People] 
set [Name] = @0 
where (([Id] = @1) and ([VerColm] = @2)) 
select [VerColm] 
from [dbo].[People] 
where @@ROWCOUNT > 0 and [Id] = @1',N'@0 nvarchar(50),@1 int,@2 binary(8)',@0=N'hello',@1=1,@2=0x0000000000000FA7 

ध्यान दें कि @ 2 0x0000000000000FA6 किया जाना चाहिए था , लेकिन यह 0x0000000000000FA7

है यहाँ VerColm अद्यतन करने के बाद अपने डेटाबेस में है: 0x0000000000000FA8


क्या कोई जानता है कि मैं इस समस्या के आसपास कैसे काम कर सकता हूं? जब मैं मौजूदा इकाई को अद्यतन करता हूं और टाइमस्टैम्प संघर्ष होता है तो मैं इकाई फ्रेमवर्क को अपवाद फेंकना चाहता हूं।

धन्यवाद

+0

कृपया कोड को सहेजने वाले कोड को पोस्ट करें। –

+0

मैं इसे पुन: उत्पन्न नहीं कर सकता। जब मैं भारित और संशोधित इकाई को टाइमस्टैम्प संघर्ष के साथ सहेजने का प्रयास करता हूं तो मुझे आशावादी कॉनकुरेंसी अपवाद मिलता है। क्या आप सुनिश्चित हैं कि आपके पास टाइमस्टैम्प संघर्ष है? क्या आप कृपया अपनी प्रोफाइल एसक्यूएल क्वेरी पोस्ट कर सकते हैं? – Jan

+0

हाय जान, मैंने आपके अनुरोध के अनुसार अतिरिक्त जानकारी जोड़ा। –

उत्तर

24

स्पष्टीकरण

कारण है कि आप अपने दूसरे कोड उदाहरण पर उम्मीद OptimisticConcurrencyException नहीं मिल रहा है ढंग एफई चेकों संगामिति की वजह से है:

जब आप द्वारा संस्थाओं को पुनः प्राप्त अपने डीबी से पूछताछ करते हुए, ईएफ मूल, अनमोडिफाइड मानों के रूप में पूछताछ के समय ConcurrencyMode.Fixed चिह्नित गुणों के साथ सभी के मान को याद करता है।

फिर आप कुछ गुणों को बदलते हैं (Fixed चिह्नित वाले सहित) और अपने डेटाकॉन्टेक्स्ट पर SaveChanges() पर कॉल करें।

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

समाधान/वर्कअराउंड

वैकल्पिक हल के लिए आप निम्न विकल्प हैं:

  1. अपना पहला दृष्टिकोण का उपयोग करें: अपनी इकाई के लिए डाटाबेस requery लेकिन अपने संदर्भ के लिए निर्मित इकाई संलग्न न करें ।

  2. नकली अपने टाइमस्टैम्प मूल्य इतना है कि एफई संगामिति जांच नीचे दिखाया गया है की तरह अपने आपूर्ति की मान का उपयोग करता है, वर्तमान डाटाबेस मूल्य होने के लिए (यह भी एक ऐसी ही सवाल पर this answer देखें):

    var currentPerson = _context.People.Where(x => x.Id == person.Id).First(); 
    currentPerson.VerColm = person.VerColm; // set timestamp value 
    var ose = _context.ObjectStateManager.GetObjectStateEntry(currentPerson); 
    ose.AcceptChanges();  // pretend object is unchanged 
    currentPerson.Name = person.Name; // assign other data properties 
    _context.SaveChanges(); 
    
  3. आप देख सकते हैं अपने आप को requeried टाइमस्टैम्प मूल्य के लिए अपनी टाइमस्टैम्प मूल्य की तुलना द्वारा संगामिति के लिए:

    var currentPerson = _context.People.Where(x => x.Id == person.Id).First(); 
    if (currentPerson.VerColm != person.VerColm) 
    { 
        throw new OptimisticConcurrencyException(); 
    } 
    currentPerson.Name = person.Name; // assign other data properties 
    _context.SaveChanges(); 
    
+0

विस्तृत स्पष्टीकरण के लिए धन्यवाद। –

5

यहाँ एक और एपी है proach कि थोड़ा अधिक सामान्य है और डेटा स्तर में फिट बैठता है:

// if any timestamps have changed, throw concurrency exception 
var changed = this.ChangeTracker.Entries<>() 
    .Any(x => !x.CurrentValues.GetValue<byte[]>("Timestamp").SequenceEqual(
     x.OriginalValues.GetValue<byte[]>("Timestamp"))); 
if (changed) throw new OptimisticConcurrencyException(); 
this.SaveChanges(); 

यह सिर्फ अगर टाइमस्टैम्प बदल गया है देखने के लिए जाँच करता है और संगामिति अपवाद फेंकता है।

+0

मैंने कोशिश की और ऐसा लगता है कि यह ठीक काम करता है।हालांकि, मैं एक समान DbUpdateConcurrencyException को फेंकना चाहता हूं क्योंकि ईएफ में संस्था संग्रह शामिल है, हालांकि, उस संग्रह के लिए कोई सेटटर नहीं है। मैंने ILSpy के साथ स्रोत में देखने की कोशिश की, लेकिन उसने बहुत सारे कोड के माध्यम से बिना किसी उपयोगी कोड को प्रकट किया (जिसमें मेरे पास समय नहीं है)। कोई भी जो जानता है कि यह कैसे किया जा सकता है? – Anttu

+0

नोट: उदाहरण कोड हटाए गए इकाइयों के लिए काम नहीं करता है। को अपडेट किया जाना चाहिए ... किसी भी (x => x.State == EntityState.Modified &&! X.CurrentValues.GetValue <.... 'अन्यथा अगर आप एक डिलीट जारी करने का प्रयास करते हैं तो एक अवैधऑपरेशन अपवाद फेंक दिया जाता है। – Anttu

+0

मैंने फिर से काम किया यह विचार मेरे डीएएल में फिट होना, बहुत अच्छा काम करता है और सरल है। धन्यवाद। – RitchieD

2

यदि यह पहले ईएफ कोड है, तो नीचे दिए गए कोड के समान कोड का उपयोग करें। यह डीआई से लोड किए गए मूल टाइमस्टैम्प को यूआई से एक में बदल देगा और यह सुनिश्चित करेगा कि OptimisticConcurrencyEception होता है।

db.Entry(request).OriginalValues["Timestamp"] = TimeStamp; 
+0

यही वह है जिसे मैं ढूंढ रहा था, धन्यवाद। –

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