why transaction transacciones practices not framework dead best c# entity-framework-6 dbcontext transactionscope savechanges

c# - transacciones - transaction entity framework 5



Usando TransactionScope con Entity Framework 6 (2)

Lo que no puedo entender es si es posible realizar cambios en el contexto y obtener los cambios en la misma transacción antes de su cometido.

Esto es lo que estoy buscando:

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

¿Puede alguien ayudarme a entender y mostrarme un patrón de trabajo?


Sí, es posible hacerlo y es muy útil cuando desea insertar una entidad en la base de datos y usar la identificación generada automáticamente para la siguiente inserción o actualización

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

Debido a que su pregunta también se refería a un patrón de trabajo, aquí está mi código de trabajo (con el uso de FluentApi, DbContext & Transaction). Estaba teniendo el mismo problema que tú :). Espero te ayude

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

Uso de la muestra:

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


Si desea asegurarse de que solo consulta el contenido local de su contexto, puede usar la colección "local":

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

Esto solo consultará los datos en memoria del contexto y no llegará a la base de datos.
Los datos "locales" están presentes tan pronto como materializa un objeto en el contexto al agregarlo o cargarlo desde la base de datos, es decir, no necesita llamar a SaveChanges ().
SaveChanges () escribirá el contenido del contexto en su base de datos.