14

के साथ ट्रांज़ेक्शनस्कोप का उपयोग करना मैं समझ नहीं पा रहा हूं कि संदर्भ में परिवर्तन करना संभव है और इसके पहले ही लेनदेन में परिवर्तन करने से पहले यह संभव है।एंटीटी फ्रेमवर्क 6

using (var scope = new TransactionScope(TransactionScopeOption.Required)) 
{ 
    using (var context = new DbContext()) 
    { 
     //first I want to update an item in the context, not to the db 
     Item thisItem = context.Items.First(); 
     thisItem.Name = "Update name"; 
     context.SaveChanges(); //Save change to this context 

     //then I want to do a query on the updated item on the current context, not against the db 
     Item thisUpdatedItem = context.Items.Where(a=>a.Name == "Update name").First(); 

     //do some more query 
    } 

    //First here I want it to commit all the changes in the current context to the db 
    scope.Complete(); 
} 

किसी की मदद कर सकते हैं मुझे समझने और मुझे एक काम पैटर्न दिखाने:

यह मैं के लिए क्या देख रहा है?

उत्तर

29

हाँ, यह करने के लिए संभव है और यह बहुत उपयोगी है जब आप अपने सवाल क्योंकि डेटाबेस करने के लिए एक इकाई डालने और अगले डालने के लिए का उपयोग स्वत: जनरेट आईडी या अद्यतन

using (var context = new DbContext())  
{ 
    using (var transaction = context.Database.BeginTransaction()) { 
     var item = new Item(); 
     context.Items.Insert(item); 
     context.SaveChanges(); // temporary insert to db to get back the auto-generated id 

     // do some other things 
     var otherItem = context.OtherItems.First(); 
     // use the inserted id 
     otherItem.Message = $"You just insert item with id = {item.Id} to database"; 
     transaction.Commit(); 
    } 
} 

करना चाहते हैं एक कामकाजी पैटर्न के बारे में भी पूछा, यहां मेरा कामकाजी कोड है (FluentApi, DbContext & लेनदेन के उपयोग के साथ)। मैं तुम्हारे जैसा ही मुद्दा था :)। आशा है कि यह आप

public class FluentUnitOfWork : IDisposable 
{ 
    private DbContext Context { get; } 

    private DbContextTransaction Transaction { get; set; } 

    public FluentUnitOfWork(DbContext context) 
    { 
     Context = context; 
    } 

    public FluentUnitOfWork BeginTransaction() 
    { 
     Transaction = Context.Database.BeginTransaction(); 
     return this; 
    } 

    public FluentUnitOfWork DoInsert<TEntity>(TEntity entity) where TEntity : class 
    { 
     Context.Set<TEntity>().Add(entity); 
     return this; 
    } 

    public FluentUnitOfWork DoInsert<TEntity>(TEntity entity, out TEntity inserted) where TEntity : class 
    { 
     inserted = Context.Set<TEntity>().Add(entity); 
     return this; 
    } 

    public FluentUnitOfWork DoUpdate<TEntity>(TEntity entity) where TEntity : class 
    { 
     Context.Entry(entity).State = EntityState.Modified; 
     return this; 
    } 

    public FluentUnitOfWork SaveAndContinue() 
    { 
     try 
     { 
      Context.SaveChanges(); 
     } 
     catch (DbEntityValidationException dbEx) 
     { 
      // add your exception handling code here 
     } 
     return this; 
    } 

    public bool EndTransaction() 
    { 
     try 
     { 
      Context.SaveChanges(); 
      Transaction.Commit(); 
     } 
     catch (DbEntityValidationException dbEx) 
     { 
      // add your exception handling code here 
     } 
     return true; 
    } 

    public void RollBack() 
    { 
     Transaction.Rollback(); 
     Dispose(); 
    } 

    public void Dispose() 
    { 
     Transaction?.Dispose(); 
     Context?.Dispose(); 
    } 
} 

नमूना उपयोग में मदद करता है:

var status = BeginTransaction() 
       // First Part 
       .DoInsert(entity1) 
       .DoInsert(entity2) 
       .DoInsert(entity3) 
       .DoInsert(entity4) 
       .SaveAndContinue() 
       // Second Part 
       .DoInsert(statusMessage.SetPropertyValue(message => message.Message, $"Just got new message {entity1.Name}")) 
      .EndTransaction(); 
+0

क्या यह डीबी में पंक्ति डालेगा और फिर यदि लेनदेन रोलबैक किया गया है तो क्या यह पंक्ति को हटा देगा? या आप पंक्ति की आईडी कैसे प्राप्त करते हैं? @ kienct89 –

+0

जब तक आप लेनदेन को कॉल नहीं करते हैं तब तक यह डीबी में पंक्ति नहीं डालेगा। कॉमिट(), आईडी अस्थायी रूप से स्मृति –

+0

मेमोरी में असाइन की जाएगी, उदाहरण और विवरण के लिए धन्यवाद। मैं इसका परीक्षण करूंगा और आपको वापस ले जाऊंगा –

2

आप यह सुनिश्चित करें कि आप केवल अपने संदर्भ से स्थानीय सामग्री आप "स्थानीय" संग्रह का उपयोग कर सकते क्वेरी बनाना चाहते हैं:

Item thisItem = context.Items.First(); 
thisItem.Name = "Update name";  
Item thisUpdatedItem = context.Items.Local.Where(a=>a.Name == "Update name").First(); 

यह केवल संदर्भ से इन-मेमोरी डेटा क्वेरी करेगा और इच्छा डेटाबेस हिट नहीं करें।
जैसे ही आप संदर्भ में किसी ऑब्जेक्ट को इसे जोड़कर या डेटाबेस से लोड करके, "स्थानीय" डेटा मौजूद होते हैं, यानी आपको SaveChanges() को कॉल करने की आवश्यकता नहीं है।
SaveChanges() आपके डेटाबेस में संदर्भ की सामग्री लिखेंगे।

+0

इस भयानक लगती है। मेरा एक सवाल है; जैसा कि kienct89 ने अपने उत्तर में वर्णित किया है, यह डीबी में स्वचालित आईडी पीढ़ी के साथ सम्मिलित करता है। क्या "स्थानीय" में कोई समान कार्य है? –

+0

नए रिकॉर्ड के लिए "स्थानीय" सिर्फ एक स्टेजिंग क्षेत्र है। जब रिकॉर्ड डाला जाता है तो आईडी डेटाबेस द्वारा प्रदान की जाती है। यह एक डेटाबेस फ़ंक्शन है, न कि ईएफ फ़ंक्शन। –

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