Error message here!

Hide Error message here!

忘记密码?

Error message here!

请输入正确邮箱

Hide Error message here!

密码丢失?请输入您的电子邮件地址。您将收到一个重设密码链接。

Error message here!

返回登录

Close

EF6学习笔记二十四:事务

张四海 2019-01-30 19:52:00 阅读数:202 评论数:0 点赞数:0 收藏数:0

要专业系统地学习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
View Code
// ado中使用事务
string connStr = @"Data Source=LAPTOP-G81QJ856\SQLEXPRESS;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;
}
}
}
}
View Code

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

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

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

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

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

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

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

这个就是开启关闭事务的开关,但是他对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();
View Code

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

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

行吧,就是这样。

如果说我们想用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();
}
View Code

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

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

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

string connStr = @"Data Source=LAPTOP-G81QJ856\SQLEXPRESS;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;
}
}
}
}
View Code

 

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

 

版权声明
本文为[张四海]所创,转载请带上原文链接,感谢
https://www.cnblogs.com/jinshan-go/p/10339589.html

编程之旅,人生之路,不止于编程,还有诗和远方。
阅代码原理,看框架知识,学企业实践;
赏诗词,读日记,踏人生之路,观世界之行;

支付宝红包,每日可领