2015-05-15 9 views
7

मेरे पास कई जुड़ाव इकाइयों के साथ एक इकाई फ्रेमवर्क परियोजना है। चूंकि इसका उपयोग कई उपयोगकर्ताओं द्वारा एक बार में किया जाता है, इसलिए मैंने इकाइयों के लिए एक रोवर्सन-फील्ड स्थापित किया है जिसे कई उपयोगकर्ताओं द्वारा एक बार में संपादित करने की संभावना है। दुर्भाग्य से अब मुझे एक नई इकाई को बचाने की कोशिश करते समय OptimisticConecurrencyException मिलता है, जो पहले से मौजूद इकाई से जुड़ा हुआ है।आशावादी Concurrency

पंक्तियों की अद्यतन अप्रत्याशित संख्या (0) प्रभावित स्टेटमेंट अपडेट, डालने या हटाएं। इकाइयों को लोड होने के बाद से इकाइयों को संशोधित या हटा दिया गया हो सकता है। आशावादी समवर्ती अपवादों को समझने और संभालने के बारे में जानकारी के लिए http://go.microsoft.com/fwlink/?LinkId=472540 देखें।

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

using (ctx = new DbContext()) 
{ 
    try 
    { 
     ctx.Samples.Add(model); 
     ctx.SaveChanges(); 
    } 
    catch (DbUpdateConcurrencyException ex) 
    { 
     LogManager.HandleException(ex.InnerException); 
    } 
} 

model मॉडल मैं

संपादित डेटाबेस में जोड़ना चाहते हैं है:

कोड मैं नई इकाई जोड़ने के लिए उपयोग इस प्रकार है देखा जैसा कि ऊपर मैं अनदेखी करने के लिए कोड को संशोधित किया एक अंतर्निहित मॉडल का अद्यतन। इसके अलावा मैंने सत्यापित किया है:

ctx.Database.log = s => Debug.Write(s); 

कि केवल एक डालने वाला स्टेटमेंट डेटाबेस को भेजा गया है और अतिरिक्त अद्यतन कथन नहीं है।

INSERT [dbo].[Samples]([IDSample], [ModificationDate], [IDUser]) 
VALUES (@0, @1, @2) 
SELECT [RowVersion] 
FROM [dbo].[Samples] 
WHERE @@ROWCOUNT > 0 AND [IDSample] = @0 AND [ModificationDate] = @1 

मैं अगर मैं एक इकाई और rowversion स्तंभ से मेल नहीं होता अपडेट करेंगे अपवाद को समझने होगा, लेकिन इस मामले में यह एक पूरी तरह से नई इकाई है। क्या यह देखने का कोई तरीका है कि गुणों में से एक विकृत है या नहीं?

EDIT2:

के बजाय सिर्फ मिलीसेकेंड अब मैं DateTime.Now DateTime.Today के बजाय जो काम करता है इस्तेमाल किया ट्रिमिंग। ऐसा लगता है कि ModificationDate पर डेटाटाइम 2 (4) के साथ कुछ समस्या है। मैंने पहले से ही यह सुनिश्चित कर लिया है कि ModificationDate को 4 मिलीसेकंड तक छोटा कर दिया गया है, इसलिए कोई पार्स त्रुटि नहीं होनी चाहिए।

Edit3:

DateTime.Now पर वापस जाने और मिलीसेकेंड यह काम करना बंद कर ट्रिमिंग और संस्थाओं अब डेटाबेस में सम्मिलित नहीं किए जाने के बाद। क्या यह इस तथ्य के कारण हो सकता है कि SQL सर्वर में मिलीसेकंड मानों के आधार पर इकाइयों से मेल खाने में समस्याएं हैं। मैंने ईएफ जेनरेट किए गए एसक्यूएल को कुछ काल्पनिक मूल्यों के साथ ऊपर देखा है और यह कुछ मौकों पर क्वेरी ने एक पंक्तिवर्तन-मूल्य वापस नहीं किया है। इकाई ढांचे के संदर्भ में, ग्राहक इसे 0 लाइनों के वापसी मूल्य के रूप में व्याख्या करेगा और इसलिए एक सहमति-अपवाद को कॉल करें। (यह भी टिप्पणी की होनी चाहिए कि एक साथ IDSample साथ ModificationDate संस्था की प्राथमिक कुंजी है।)

Edit4:

मैं अब DateTime.Today उपयोग कर रहा हूँ और उसके बाद जरूरत सटीक है, जो काम करता है जोड़ने मेरे लिए। इसे हल के रूप में चिह्नित किया जा सकता है। (Altough मुझे उम्मीद थी कि ईएफ डेटाटाइम-प्रारूप-रूपांतरण का ख्याल रख सकता है: /)

+0

मुझे नहीं लगता कि मान्यता 'से निकाल देते थे DbUpdateConcurrencyException' – Dusan

+1

मॉडल एक क्षेत्र है कि के उदाहरण के लिए की तरह छोटा कर दिया मिलता है, तो है एक गलत datetime2 प्रारूप और इसलिए डेटाबेस किसी भी पंक्ति को नहीं लिखता है और 0 देता है यह एक समवर्ती अपवाद को आग लगा देगा। यह उन त्रुटियों में से एक है जो मुझे पहले से मिला है। – narain

+0

आपका मतलब है कि यह आपको नहीं देता है कि मॉडल में कौन सा क्षेत्र वर्तमान में पंक्ति से अलग है? – Dusan

उत्तर

1

मेरे पास सवाल यह है कि आप डेटटाइम कहां/जोड़ रहे हैं? आप इस समस्या को हथियाने के लिए बहुत सारे कदम उठा रहे हैं। एक डाटाटाइम बनाना, इसे संशोधित करना आदि।

यदि आप इकाई मैप किए गए गुणों के साथ बेस क्लास से विरासत में हैं, तो SaveChanges() के DbContext ओवरराइड में अपनी सहमति जोड़ें/अपडेट करें।

यहाँ एक उदाहरण है: (अनुकूलित वाक्य रचना बिना लिखा)

public abstract class EntityBase 
{ 
    public int Id {get; set;} 
    public DateTime CreationDate {get; set;} 
    public DateTime? ModifyDate {get; set;} 
    public string VersionHash {get; set;} 
} 
public static class EntityBaseExtensions 
{ 
    public static void MyBaseEntityMapping<T>(this EntityTypeConfiguration<T> configuration) where T : EntityBase 
    { 
     configuration.HasKey(x => x.Id); 
     configuration.Property(x => x.CreationDate) 
           .IsRequired(); 
     configuration.Property(x => x.ModifyDate) 
           .IsOptional(); 
     configuration.Property(x => x.VersionHash).IsConcurrencyToken(); 
    } 
} 
public class MyEntity : EntityBase 
{ 
    public string MyProperty {get; set;} 
} 
public class MyEntityMapping : EntityTypeConfiguration<MyEntity> 
{ 
    public MyEntityMapping() 
    { 
     this.MyBaseEntityMapping(); 
     Property(x=>x.MyProperty).IsRequired(); 
    } 
} 

public class MyContext : DbContext 
{ 
    .... 
    public override int SaveChanges() 
    { 
     this.ChangeTracker.DetectChanges(); //this forces EF to compare changes to originals including references and one to many relationships, I'm in the habit of doing this. 

     var context = ((IObjectContextAdapter)this).ObjectContext; //grab the underlying context 
     var ostateEntries = context.ObjectStateManager.GetObjectStateEntries(EntityState.Modified | EntityState.Added); // grab the entity entries (add/remove, queried) in the current context 

     var stateEntries = ostateEntries.Where(x => x.IsRelationship == false && x.Entity is EntityBase); // don't care about relationships, but has to inherit from EntityBase 

     var time = DateTime.Now; //getting a date for our auditing dates 

     foreach (var entry in stateEntries) 
     { 
      var entity = entry.Entity as EntityBase; 
      if (entity != null) //redundant, but resharper still yells at you :) 
      { 
       if (entry.State == EntityState.Added) //could also look at Id field > 0, but this is safe enough 
       { 
        entity.CreationDate = time; 
       } 
       entity.ModifyDate = time; 
       entity.VersionHash = Guid.NewGuid().ToString().Replace("-", "").Substring(0, 10); //this an example of a simple random configuration of letters/numbers.. since the query on sql server is primarily using the primary key index, you can use whatever you want without worrying about query execution.. just don't query on the version itself! 
      } 
     } 
     return base.SaveChanges(); 
    } 
    .... 
} 
संबंधित मुद्दे