• EF6学习笔记二十四:事务


    要专业系统地学习EF推荐《你必须掌握的Entity Framework 6.x与Core 2.0》。这本书作者(汪鹏,Jeffcky)的博客:https://www.cnblogs.com/CreateMyself/

    了解一下EF中事务。首先复习一下原始的SQL语句创建事务,然后也复习一下ADO中事务的使用。工作一年多我就没写过事务,因为用的是EF,事务就只是在学校中写过。

    详细学习事务:https://www.cnblogs.com/knowledgesea/p/3714417.html  

    复制代码
    begin transaction
    begin try
         insert into tb_Students values(newid(),'小明','44','2012-1-1');
         insert into tb_Teachers values(newid(),'张四海','语文','2018-2-2');
    end try
    begin catch
        select ERROR_NUMBER() as ErrorNumber,  --  错误代码
                    ERROR_SEVERITY() as ErrorSeverity,-- 错误严重级别,级别小于10,try catch捕获不到
                    ERROR_STATE() as ErrorState, -- 错误状态码
                    ERROR_PROCEDURE() as ErrorProcedure,  --  出现错误的存储过程或触发器的名称
                    ERROR_LINE() as ErrorLine,  --  发生错误的行号
                    ERROR_MESSAGE() as ErrorMessage  --  错误的具体信息
        if(@@TRANCOUNT > 0)  --  事务开启此值+1,判断是否开启事务
              rollback transaction
    end catch
    if(@@TRANCOUNT > 0)
    commit tran
    复制代码
    复制代码
    //  ado中使用事务
    string connStr = @"Data Source=LAPTOP-G81QJ856SQLEXPRESS;Initial Catalog=_20190130.EFDbContext;Integrated Security=True";
    using (SqlConnection conn = new SqlConnection(connStr))
    {
        Console.WriteLine(conn.State);  //  closed  我还以为使用using自动打开的
        conn.Open();
        string sql = @"insert into tb_Students values(newid(),'小强','44','2012-1-1');insert into tb_Teachers values(newid(),'张抛','数学','1999-9-2');";
        using (SqlCommand cmd = new SqlCommand(sql, conn))
        {
            using (SqlTransaction tran = conn.BeginTransaction())
            {
                try
                {
                    //  如果不告诉cmd使用哪个事务会报错
                    ////  System.InvalidOperationException: 如果分配给命令的连接位于本地挂起事务中,ExecuteNonQuery 要求命令拥有 事务。命令的 Transaction 属性尚未初始化。
                    cmd.Transaction = tran; 
                    var i = cmd.ExecuteNonQuery();
                    tran.Commit();
                }
                catch (Exception e)
                {
                    tran.Rollback();
                    throw e;  
                }
            }
        }
    }
    复制代码

    现在来看看EF中事务是怎么回事

    我们平时在执行添加、修改、删除调用SaveChanges方法时,这些操作默认就会被事务包裹。查询操作则没有。

    ctx.Students.Add(new Student { Name = "小刘", Score = "55", AddTime = DateTime.Now });

     当我们多次调用SaveChanges时,就会开启多个事务。

    ctx.Students.Add(new Student { Name="小新",Score="66"});
    ctx.SaveChanges();
    ctx.Teachers.Add(new Teacher { Name="胡飘",Subject="历史"});
    ctx.SaveChanges();

    现在来看EF中的一个关于事务的开关

    复制代码
    public class EFDbContext : DbContext
        {
            public EFDbContext()
            {
                //此标志确定在使用此类方法时是否启动新事务
                Configuration.EnsureTransactionsForFunctionsAndCommands = false;
            }
    }
    复制代码

    这个就是开启关闭事务的开关,但是他对SaveChanges是不起作用的,目前我只知道调用ExecuteSqlCommand方式时才有用。MSDN上对这个说的很简陋

    那么看看EF中对这个属性的注释

    还是直接使用它来看看。下面这条语句我关闭事务, 添加一条记录,然后调用SaveChanges,但其实,还是会开启事务

      //  还是会有事务的            ctx.Configuration.EnsureTransactionsForFunctionsAndCommands = false;
    ctx.Database.Log = msg => Console.WriteLine(msg);
    ctx.Teachers.Add(new Teacher { Name = "胡愤", Subject = "历史" });
    ctx.Students.Add(new Student { Name = "小赵", Score = "66", AddTime = DateTime.MinValue });
    ctx.SaveChanges();

    ExecuteSqlCommand也是默认被事务包裹,但是他就可以通过传递参数来实现事务的开启和关闭。

    ctx.Database.ExecuteSqlCommand(TransactionalBehavior.DoNotEnsureTransaction, @"insert into tb_students values(newid(),'小刘','70',getdate())");

    行吧,就是这样。

    如果说我们想用ADO中那种方式来使用事务呢?当然是可以的,上下文提供了BeginTransaction,和ADO中的命名是一样的。

    复制代码
    using (var transaction = ctx.Database.BeginTransaction())
    {
        ctx.Teachers.Add(new Teacher { Name = "胡愤", Subject = "历史" });
        ctx.SaveChanges();
        ctx.Students.Add(new Student { Name = "小赵", Score = "66", AddTime = DateTime.Now });
        ctx.SaveChanges();
        transaction.Commit();
    }
    复制代码

     我虽然调用了两次saveChanges,但只有一个事务,但是必须要调用一次SaveChanges才能成功插入

    最后开看一下EF提供的UseTransaction方法,这个是什么意思呢?允许上下文参与到已存在的事务中。

    我们现在使用ADO,将ADO的transaction对象传递给EF的UseTransaction,那么我在ADO中的操作和在EF中的操作就可以处在同一个事务中

    复制代码
    string connStr = @"Data Source=LAPTOP-G81QJ856SQLEXPRESS;Initial Catalog=_20190130.EFDbContext;Integrated Security=True";
    using (SqlConnection conn = new SqlConnection(connStr))
    {
        conn.Open();
        string sql = @"insert into tb_students values(newid(),'小蓝 ','70',getdate())";
        using (SqlCommand cmd = new SqlCommand(sql, conn))
        {
            using (SqlTransaction tran = conn.BeginTransaction())
            {
                try
                {
                    cmd.Transaction = tran;
                    var i = cmd.ExecuteNonQuery();
                    using (EFDbContext ctx = new EFDbContext(conn))
                    {
                        ctx.Database.UseTransaction(tran);
                        ctx.Students.Add(new Student { Name = "小红", Score = "55", AddTime = DateTime.Now });
                        ctx.SaveChanges();
                    }
                    tran.Commit();
                }
                catch (Exception e)
                {
                    tran.Rollback();
                    throw e;
                }
            }
        }
    }
    复制代码

     行吧,EF中简单的事务就到这里了。

  • 相关阅读:
    linux 配置Apache 、PHP
    SQL Server DML(SELECT)常见用法(二)
    SQL Server DML(UPDATE、INSERT、DELETE)常见用法(一)
    PropertyGrid—添加EventTab
    PropertyGrid—添加属性Tab
    PropertyGrid—默认属性,默认事件,属性默认值
    PropertyGrid—为复杂属性提供下拉式编辑框和弹出式编辑框
    PropertyGrid--为复杂属性提供编辑功能
    PropertyGrid--基本功能
    Intellij IDEA使用(一)项目模板类型
  • 原文地址:https://www.cnblogs.com/anyihen/p/12819747.html
Copyright © 2020-2023  润新知