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?
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.
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.
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 .
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();
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With