简体   繁体   English

将 TransactionScope 与实体框架 6 一起使用

[英]Using TransactionScope with Entity Framework 6

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?有人可以帮助我理解并向我展示工作模式吗?

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 是的,它可以做,当你想要一个实体插入数据库并使用自动生成的id进行下一次插入或更新时它非常有用

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). 因为您的问题也询问了工作模式,这是我的工作代码(使用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 want to make sure that you only query the local content of your context you can use the "local" collection: 如果您想确保只查询上下文的本地内容,可以使用“本地”集合:

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

This will only query the in-memory data of the context and will not hit the database. 这将仅查询上下文的内存中数据,并且不会访问数据库。
The "Local" data is present as soon as you materialize an object in the context by adding it or loading it from the database, ie you do not need to call SaveChanges(). 只要您通过添加或从数据库加载对象来实现上下文中的对象,就会出现“本地”数据,即您不需要调用SaveChanges()。
SaveChanges() will write the content of the context to your database. SaveChanges()会将上下文的内容写入您的数据库。

In my experience creating the context isn't necessary, I like to simplify as much as I can, and also if you require code to be hit in the case of a rollback surround the transaction with a try catch.根据我的经验,创建上下文不是必需的,我喜欢尽可能地简化,并且如果您需要在回滚的情况下命中代码,请使用 try catch 围绕事务。

try
{
   using (var scope = new TransactionScope(TransactionScopeOption.Required))
   {
          ...do stuff

          scope.Complete();
   }
}
catch (Exception)
{
  ...do stuff
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 在Entity Framework中使用TransactionScope查询是个好主意吗? - Is using TransactionScope in Entity Framework queries a good idea? TransactionScope和实体框架 - TransactionScope and Entity Framework 实体框架TransactionScope回滚问题 - Entity Framework TransactionScope rollback issue 如何在实体框架中使用TransactionScope - How to use TransactionScope in Entity Framework 为什么TransactionScope不能与Entity Framework一起使用? - Why doesn't TransactionScope work with Entity Framework? 在Entity Framework 4.1中使用TransactionScope的多个dbcontext的SaveChanges() - SaveChanges() for multiple dbcontext with TransactionScope in Entity Framework 4.1 实体框架:TransactionScope具有不同的IsolationLevel - Entity Framework: TransactionScope has a different IsolationLevel 在 Entity Framework Core 3 中使用 TransactionScope 时,SET IDENTITY_INSERT 不起作用 - SET IDENTITY_INSERT not working when using TransactionScope in Entity Framework Core 3 在不跨越多个上下文对象的情况下,Entity Framework 4中的TransactionScope是否有用途? - Are there uses for TransactionScope in Entity Framework 4 in situations that do not span multiple context objects? TransactionScope是否适合在实体框架事务中包含副作用? - Is a TransactionScope appropriate to include side effects in the Entity Framework transaction?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM