2011-10-07 16 views
5

कॉल करता है मैं बैच प्रसंस्करण प्रणाली का निर्माण कर रहा हूं। Units के बैच 20-1000 से मात्रा में आते हैं। प्रत्येक Unit अनिवार्य रूप से मॉडल का एक पदानुक्रम (एक मुख्य मॉडल और कई बाल मॉडल) है। मेरे कार्य में प्रत्येक मॉडल पदानुक्रम को एक लेनदेन के रूप में डेटाबेस में सहेजना शामिल है (या तो प्रत्येक पदानुक्रम करता है या यह वापस रोल करता है)। दुर्भाग्यवश EF हजारों रिकॉर्ड रखने की उनकी क्षमता के कारण मॉडल पदानुक्रम के दो हिस्सों को संभालने में असमर्थ था।ईएफ प्रतिस्पर्धा SaveChanges()

मैंने इसे हल करने के लिए क्या किया है, इन दो संभावित उच्च गिनती मॉडल को संभालने के लिए SqlBulkCopy स्थापित किया गया है और EF शेष आवेषण (और संदर्भित अखंडता) को संभालने दें।

बैच लूप:

foreach (var unitDetails in BatchUnits) 
{ 
    var unitOfWork = new Unit(unitDetails); 
    Task.Factory.StartNew(() => 
    { 
     unitOfWork.ProcessX(); // data preparation 
     unitOfWork.ProcessY(); // data preparation 
     unitOfWork.PersistCase(); 
    }); 
} 

इकाई:

class Unit 
{ 
    public PersistCase() 
    { 
    using (var dbContext = new CustomDbContext()) 
    { 
     // Need an explicit transaction so that 
     // EF + SqlBulkCopy act as a single block 
     using (var scope = new TransactionScope(TransactionScopeOption.Required, 
     new TransactionOptions() { 
      IsolationLevel = System.Transaction.IsolationLevel.ReadCommitted 
     })) 
     { 
     // Let EF Insert most of the records 
     // Note Insert is all it is doing, no update or delete 
     dbContext.Units.Add(thisUnit); 
     dbContext.SaveChanges(); // deadlocks, DbConcurrencyExceptions here 

     // Copy Auto Inc Generated Id (set by EF) to DataTables 
     // for referential integrity of SqlBulkCopy inserts 
     CopyGeneratedId(thisUnit.AutoIncrementedId, dataTables); 

     // Execute SqlBulkCopy for potentially numerous model #1 
     SqlBulkCopy bulkCopy1 = new SqlBulkCopy(...); 
     ... 
     bulkCopy1.WriteToServer(dataTables["#1"]); 

     // Execute SqlBulkCopy for potentially number model #2 
     SqlBulkCopy bulkCopy2 = new SqlBulkCopy(...); 
     ... 
     bulkCopy2.WriteToServer(dataTables["#2"]); 

     // Commit transaction 
     scope.Complete(); 
     } 
    } 
    } 
} 

अभी मैं अनिवार्य रूप से एक रॉक और एक मुश्किल जगह के बीच फंस कर रहा हूँ। अगर मैं IsolationLevel को ReadCommitted पर सेट करता हूं, तो मुझे विभिन्न Tasks में EFINSERT कथन के बीच deadlocks मिलते हैं।

IsolationLevelReadUncommitted (जो मैं ठीक हो जाएगा सोचा था कि जब से मैं किसी भी SELECTs नहीं कर रहा हूँ) मैं DbConcurrencyExceptions मिलता है मैं निर्धारित किया है।

मैं DbConcurrencyExceptions और Entity Framework के बारे में कोई अच्छा जानकारी प्राप्त करने में असमर्थ रहा हूँ, लेकिन मुझे लगता है कि ReadUncommitted अनिवार्य रूप से EF जानकारी अमान्य "डाला पंक्तियों" प्राप्त करने के लिए खड़ी कर रहा है अनुमान लगा रहा हूँ।

अद्यतन

यहाँ क्या वास्तव में मेरे मुद्दों deadlocking जबकि आवेषण कर खड़ी कर रहा है पर कुछ पृष्ठभूमि जानकारी है:

http://connect.microsoft.com/VisualStudio/feedback/details/562148/how-to-avoid-using-scope-identity-based-insert-commands-on-sql-server-2005

जाहिर है यह एक ही मुद्दा कुछ साल पहले मौजूद था जब Linq करने के लिए एसक्यूएल बाहर आया और माइक्रोसॉफ्ट ने यह तय करके इसे ठीक किया कि scope_identity() कैसे चुना जाता है। यह सुनिश्चित नहीं है कि एक ही समस्या इकाई फ्रेमवर्क के साथ आने पर SQL स्थिति समस्या होने पर उनकी स्थिति क्यों बदल गई है।

+0

_competing_ या _completing_? –

उत्तर

3

यह समस्या काफी अच्छी तरह से यहाँ समझाया गया है: http://connect.microsoft.com/VisualStudio/feedback/details/562148/how-to-avoid-using-scope-identity-based-insert-commands-on-sql-server-2005

अनिवार्य रूप से अपनी एक आंतरिक एफई मुद्दा। मैंने लिंक टू एसक्यूएल का उपयोग करने के लिए अपना कोड माइग्रेट किया और अब यह ठीक काम करता है (अब पहचान मूल्य के लिए अनावश्यक SELECT नहीं करता है)। Linq करने के लिए Sql में ठीक उसी मुद्दा जो तय किया गया था से

प्रासंगिक बोली:

एक मेज एक पहचान स्तंभ है, तो LINQ एसक्यूएल के लिए इस तरह के एक तालिका में प्रविष्टि के लिए अत्यंत अक्षम एसक्यूएल उत्पन्न करता है। मान लें कि तालिका ऑर्डर और पहचान कॉलम आईडी है। जेनरेट किया गया एसक्यूएल है:

exec sp_executesql N'INSERT INTO [dbo]।[आदेश] ([Colum1], [Column2]) मान (@ p0, @ p1)

का चयन करें [t0]। [आईडी] [dbo] से। [आदेश] के रूप में [t0] जहां [t0]। [ईद] = (SCOPE_IDENTITY()) ', एन' @ p0 पूर्णांक, @ p1 पूर्णांक, @ p0 = 124, @ p1 = 432

एक SCOPE_IDENTITY (लौटने के बजाय देख सकते हैं) सीधे का उपयोग करके ' SCOPE_IDENTITY() 'चुनें, जेनरेट किया गया एसक्यूएल SCOPE_IDENTITY() द्वारा दिए गए मान का उपयोग करके आईडी कॉलम पर एक चयन करता है। जब तालिका में रिकॉर्ड्स की संख्या बड़ी है, तो यह सम्मिलन के नीचे धीमा हो जाती है। जब तालिका विभाजित होती है, तो समस्या और भी बदतर हो जाती है।

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