Utilisation de TransactionScope avec Entity Framework 6

c# dbcontext entity-framework-6 savechanges transactionscope

Question

Ce que je ne comprends pas, c'est s'il est possible d'apporter des modifications au contexte et d'obtenir les modifications dans la même transaction avant sa validation.

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

Est-ce que quelqu'un peut m'aider à comprendre et me montrer un schéma de travail?

Réponse acceptée

Oui, c'est possible et très utile lorsque vous souhaitez insérer une entité dans une base de données et utiliser l'identifiant généré automatiquement pour l'insertion ou la mise à jour suivante

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

Puisque votre question concerne également 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 toi :). J'espère que ça 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();

Réponse populaire

Si vous voulez vous assurer que vous interrogez uniquement le contenu local de votre contexte, vous pouvez utiliser la collection "local":

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 ne touchera 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; vous n'avez donc pas besoin d'appeler SaveChanges ().
SaveChanges () écrira le contenu du contexte dans votre base de données.



Related

Sous licence: CC-BY-SA with attribution
Non affilié à Stack Overflow
Sous licence: CC-BY-SA with attribution
Non affilié à Stack Overflow