zoukankan      html  css  js  c++  java
  • EntityFramework 事务处理

    默认情况下,当EF调用SaveChanges()时,会把生成的所有SQL命令“包”到一个“事务(transaction)”中,只要有一个数据更新操作失败,整个事务将回滚。

    在多数情况下,如果你总在数据更新操作代码中使用一个而不是多个DbContext对象,并且只是在最后调用一次SaveChanges(),那么EF的默认事务处理机制己经够用了,无需做额外的事情。

    然而,如果出现以下的情形,你就必须显式地处理事务了。

    第一种情况:你需要分阶段地保存数据,因而需要多次调用SaveChanges()或者执行修改数据库的SQL命令。

    请看以下示例代码:

    using (var context = new MyDbContext())
    
    {
        try
         {
            Person3 p = context.People3.First();
    
            p.Name ="newName" + (new Random().Next(1, 100));
    
            context.SaveChanges();
    
            context.Database.ExecuteSqlCommand("update Person3 setDescription={0} where Person3Id={1}",
    
                                "DescriptionModified at " + DateTime.Now.ToShortTimeString(),
    
                                p.Person3Id);
            p.age *= 2;
            context.SaveChanges();
        }
        catch (Exception e)
        {
            Console.WriteLine(e.Message);
         }
    }

    上述代码中,调用两次SaveChanges(),还有一次执行Update命令。

    如果在最后一次SaveChanges()中出现异常,虽然最后一次没成功,但你会发现前两次数据己经保存!这就带来了数据不一致的问题。

    对于这种场景,你需要显式地编写事务代码了(注:以下代码适用于EF6):

    using (var context = new MyDbContext())
     {
        using (var transaction =context.Database.BeginTransaction())
        {
            try
            {
                  ……
    
                  context.SaveChanges();
    
                  context.Database.ExecuteSqlCommand("……);
    
                  ……
    
                  context.SaveChanges();
                  transaction.Commit();
    
             }
            catch (Exception e)
            {
                   Console.WriteLine(e.Message);
                   transaction.Rollback();
            }
        }
    }
    

    特别要注意一定要调用commit(),我测试发现,只要不Commit,即使没有异常发生,事务仍将回滚,数据库中的数据不会更新。

    第2种情况,你需要使用多个DbContext保存数据

    以下是处理这种场景的典型代码:

    static void TestTransactionScope2()
    
    {
               using (TransactionScope scope = new TransactionScope())
               {
                    String connStr = ……;
                    using (var conn = newSqlConnection(connStr))
                    {
                        try
                        {
                            conn.Open();
                            using (var context1 =new MyDbContext(conn, contextOwnsConnection: false))
                            {
                                 ……
                                 context1.SaveChanges();
                            }
                          using (var context2 =new MyDbContext(conn, contextOwnsConnection: false))
                           {
                               context2.Database.ExecuteSqlCommand(……);
                               context2.SaveChanges();
                           }
                           using (var context3 =new MyDbContext2(conn, contextOwnsConnection: false))
                           {
                                ……
                                context3.SaveChanges();
                           }
                          scope.Complete();
                     }
                    catch (Exception e)
                    {
                           Console.WriteLine(e.ToString());
                    }
                    finally
                    {
                            conn.Close();
                     }
                }
          }
    }
    

    上述代码中有几个关键点:

    (1)在构造DbContext对象时,需要把一个己打开的数据库连接对象传给它,并且需要指定EF在DbContext对象销毁时不关闭数据库连接。

    为实现此目的,你的DbContext对象应该类似于是这样的,提供两个重载的构造函数:

    public class MyDbContext2 : DbContext
        {
    
           public MyDbContext2(DbConnection conn, boolcontextOwnsConnection):base(conn,contextOwnsConnection)
           {
    
           }
    
           public MyDbContext2():base()
           {
    
           }
           public DbSet<OtherEntity> OtherEntities { get; set; }
    
           ……
    }
    

    注意在代码结束时关闭连接。

    (2)如果不Commit,则所有数据将不会保存。

    (3)你的计算机需要启动MSDTC(分布式交易协调器),请先在控制面板中打开Distributed Transaction Coordinator服务,否则上述代码将在运行时抛出MSDTC服务不可用的异常。

    很明显,当事务需要使用多个不同类型的DbContext对象时,Windows需要启动MSDTC,这会对性能有所影响,因此在开发中应该尽量避免这种情况,如无必要,不要在单个事务中使用多个不同种类的DbContext对象。

    转自:http://blog.csdn.net/bitfan/article/details/14231561

  • 相关阅读:
    JS BOM对象 History对象 Location对象
    JS 字符串对象 数组对象 函数对象 函数作用域
    JS 引入方式 基本数据类型 运算符 控制语句 循环 异常
    Pycharm Html CSS JS 快捷方式创建元素
    CSS 内外边距 float positio属性
    CSS 颜色 字体 背景 文本 边框 列表 display属性
    【Android】RxJava的使用(三)转换——map、flatMap
    【Android】RxJava的使用(二)Action
    【Android】RxJava的使用(一)基本用法
    【Android】Retrofit 2.0 的使用
  • 原文地址:https://www.cnblogs.com/hycms/p/5384560.html
Copyright © 2011-2022 走看看