Ce que je ne peux pas comprendre, c'est s'il est possible d'apporter des modifications au contexte et d'obtenir les modifications dans la même transaction avant qu'elle ne soit validée.
Voici ce que je recherche:
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();
}
Quelqu'un peut-il m'aider à comprendre et à me montrer un schéma de travail?
Oui, c'est possible et c'est très utile lorsque vous voulez insérer une entité dans la base de données et utiliser l'id généré automatiquement pour la prochaine insertion ou mise à jour
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();
}
}
Parce que votre question portait également sur un modèle de travail, voici mon code de travail (avec l'utilisation de FluentApi, DbContext & Transaction). J'avais le même problème que vous :). J'espère que cela vous aide
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();
}
}
Exemple d'utilisation:
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 vous voulez vous assurer que vous interrogez uniquement le contenu local de votre contexte, vous pouvez utiliser la collection "locale":
Item thisItem = context.Items.First();
thisItem.Name = "Update name";
Item thisUpdatedItem = context.Items.Local.Where(a=>a.Name == "Update name").First();
Cela interrogera uniquement les données en mémoire du contexte et n'atteindra pas la base de données.
Les données "locales" sont présentes dès que vous matérialisez un objet dans le contexte en l'ajoutant ou en le chargeant à partir de la base de données, c'est-à-dire que vous n'avez pas besoin d'appeler SaveChanges ().
SaveChanges () écrira le contenu du contexte dans votre base de données.