【问题标题】:Use external System.Common.DBTransaction with Entity Framework 5将外部 System.Common.DBTransaction 与 Entity Framework 5 一起使用
【发布时间】:2016-10-31 09:45:39
【问题描述】:

我遇到了一个问题,该问题将在 ADO.NET 中与实体框架上下文混合时发生在每个人身上。 我有一个大程序,通过使用多种方式(如 ADO.NET 数据适配器和针对 DB 的直接 CRUD 命令)来处理并将数据保存到数据库中。所有过程都由 2 个 using() 块包装,这些块创建和释放一个 DBConnection/DBTransaction 和一个 try/catch 块以提交或回滚事务。不幸的是,在这个例程的中间,我不得不回忆一个使用实体框架实现的保存过程。这给我带来了一个问题:

根据官方文档,Entity Framework 5 允许我通过与事务相关的事务的连接(它应该在调试模式下工作,当我调用 SaveChanges() 时,由于死锁,我没有收到任何 TimeOutException,相反如果我通过了一个新的连接,它确实如此),但不幸的是,在 SaveChanges() 启动后,连接关闭并提交了关联的事务!即使我设置了“contextOwnsConnection”标志!

据我所知,如果我将 EF5 迁移到 EF6,事情应该可以工作(对吗?),但不幸的是我不能,因为我正在处理的项目非常大并且涉及很多依赖项这将花费大量时间。

如何使它与 EF5 一起使用?是否有任何技巧或模式来达到预期的结果?我对 EF6 的行为是否正确?是否值得迁移 EF6?

这是一个简单的示例,说明我的代码是什么样的。 出于隐私原因,我无法发布原始代码,只是想象一下这种情况更加复杂:

   using(DbConnection conn = DBProvider.CreateConnection()){

            //Open the created connection
            conn.Open();

            //Create a new transaction
            using(DbTransaction tr = DBProvider.CreateTransaction()){

              //Begin a new transaction
              tr.Begin();

              bool saveOk;
              try{

                  //Updates customers by using dataadapter
                  dataAdapterCustomers.InsertCommand.Transaction = tr; 
                  dataAdapterCustomers.UpdateCommand.Transaction = tr;
                  dataAdapterCustomers.DeleteCommand.Transaction = tr;
                  dataAdapterCustomers.Update();

                  //Updates stock items by using dataadapter
                  stockAdapterCustomers.InsertCommand.Transaction = tr; 
                  stockAdapterCustomers.UpdateCommand.Transaction = tr;
                  stockAdapterCustomers.DeleteCommand.Transaction = tr;
                  stockAdapterCustomers.Update();  

                  //...Many other DB accessing here... 

                  //Updates stock quantity by using simple DBCommand
                  quantityUpdateCmd.Transaction = tr;
                  quantityUpdateCmd.ExecuteNonQuery();

                  //Updates stock statistics by using a simple DBCommand
                  updateStockStatsCmd.Transaction = tr;
                  updateStockStatsCmd.ExecuteNonQuery();


                  //...Many other DB accessing here... 

                  //HERE:
                  //Creates a new activity and save it using EF.
                  //I use a UnitOfWork and i pass to it my connection and 'false' as contextOwnsConnection parameter 
                  //(it 'll be used by the DBContext contained in my Unit of work)
                  using(ActivityUoW uow = new ActivityUoW(conn, false)){

                     Activity act = new Activity();
                     act.Name = "Saving activity";
                     act.Description = "Done by user";
                     act.Date = DateTime.Now;

                     uow.Activities.Add(act);
                     uow.SaveChanges();
                   }


                  //Based on activity result, launch a store procedure that makes other complex things. 
UNFORTUNATELY THE CONNECTION HAS BEEN CLOSED AND TRANSACTION COMMITTED, SO THE FOLLOWING INSTRUCTION WILL FAIL.

                  launchActivityUpdateSpCmd.Transaction = tr;
                  launchActivityUpdateSpCmd.ExecuteNonQuery();


                   //...Many other DB accessing here... 

                   //Data saved correctly  
                   saveOk = true;

               }
               catch(Exception ex){

                  //There was an error during save
                  saveOk = false;
               }


               //Commit or rollback transaction according to save procedure result 
               if(saveOk) 
                 tr.Commit();
               else
                 tr.Rollback();
            }
        }

【问题讨论】:

    标签: c# entity-framework transactions ado.net dbconnection


    【解决方案1】:

    我没有完全理解您的问题,也不确定您的问题是否与如何处理事务有关,或者您是否对 EF5 到 EF6 迁移有疑问。话虽如此,您有一个有趣的数据访问代码组合。

    关于事务 - 我会考虑使用 TransactionScope,它是 System.Transactions 命名空间的一部分。

    例如:

        try
        {
            using (var scope = new TransactionScope())
            {
                using (var conn = new SqlConnection("your connection string"))
                {
                    conn.Open();
                    // your EF and ADO.NET code
                }
    
                scope.Complete();
            }
        }
        catch (TransactionAbortedException ex)
        {
    
        }
        catch (ApplicationException ex)
        {
    
        }
    

    【讨论】:

    • TransactionScope 听起来不错,它应该适用于在我的范围内设置事务。但是在 EF SaveContext() 之后关闭连接呢? EF 是否让 DbConnection 在事务范围内保持打开状态?如果我不这样做,除了从 EF5 迁移到 EF6 之外我还能做什么?
    • 您的连接对象在 using 块中。连接将被关闭。使用块调用 Dispose()。
    • 是的,我知道,但是 launchActivityUpdateSpCmd 命令呢?它不起作用,因为此时连接已经由于前几行代码的 EF5 SaveChanges() 行为而关闭。
    • 它不适用于您当前的代码?还是使用 TransactionScope 不起作用?
    • 当前代码没有运行,我还没有尝试过使用TransactionScope,因为实际情况很复杂,所以我问你是否了解EF5的自动关闭连接,即使连接iis由客户端传递;-)
    猜你喜欢
    • 2011-06-22
    • 1970-01-01
    • 2015-10-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多