Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using TransactionScope with Entity Framework 6

Tags:

What I can't understand is if its possible to make changes to the context and get the changes in the same transaction before its commited.

This is what I´m looking for:

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();  }  

Can someone help me understand and show me a working pattern?

like image 201
Marcus Höglund Avatar asked Dec 04 '15 08:12

Marcus Höglund


People also ask

Does TransactionScope work with Entity Framework?

Entity Framework is already operating within a TransactionScope. The connection object in the transaction passed is null. That is, the transaction is not associated with a connection – usually this is a sign that that transaction has already completed.

Should I use EF core transactions?

Default transaction behavior This means that SaveChanges is guaranteed to either completely succeed, or leave the database unmodified if an error occurs. For most applications, this default behavior is sufficient. You should only manually control transactions if your application requirements deem it necessary.

How do I use SaveChanges in Entity Framework?

The SaveChanges method of the DbContext prepares the Insert , Update & Delete Queries. It does so by tracking the changes to each of the entities' Context is tracking. Whenever we query the database for entities, the Context retrieves them and mark the entity as Unchanged .


1 Answers

Yes, it's possible to do and it's very useful when you want to insert a entity to database and use the auto-generated id for the next insert or update

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();     } }  

Because your question also asked about a working pattern, here's my working code (with use of FluentApi, DbContext & Transaction). I was having the same issue as you :). Hope it helps you

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();     } } 

Sample usage:

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(); 
like image 54
Kien Chu Avatar answered Sep 19 '22 13:09

Kien Chu