EF 事务(转载)

时间:2022-08-31 22:17:45

事务简单用法

文章一:https://www.cnblogs.com/wujingtao/p/5407821.html

1EF事务

事务就是确保一次数据库操作,所有步骤都成功,如果哪一步出错了,整个操作都将回滚。

在EF使用事务有两种方案,一种是EF自带的.BeginTransaction()方法,另一种是使用TransactionScope类。

使用.BeginTransaction()

使用.BeginTransaction()实现事务

class Program
{
static void Main(string[] args)
{
using (var db = new DBModel())
{
var tran = db.Database.BeginTransaction(); //开启事务 try
{
var student = db.students.FirstOrDefault(s => s.name == "萝莉");
db.students.Remove(student); //删除萝莉 db.SaveChanges(); tran.Commit(); //必须调用Commit(),不然数据不会保存
}
catch (Exception ex)
{
tran.Rollback(); //出错就回滚
}
}
}
}

  

使用TransactionScope类

使用之前记得引入System.Transactions.dll

使用TransactionScope

class Program
{
static void Main(string[] args)
{
using (var db = new DBModel())
{
using (var tran = new TransactionScope()) //开启事务
{
var student = db.students.FirstOrDefault(s => s.name == "萝莉");
db.students.Remove(student); //删除萝莉 db.SaveChanges(); tran.Complete(); //必须调用.Complete(),不然数据不会保存
} //出了using代码块如果还没调用Complete(),所有操作就会自动回滚
}
}
}

文章二:https://www.cnblogs.com/CreateMyself/p/4787856.html#!comments

事务复杂用法

1概念

在开始学习事务之前我们先了解两个概念:

  • Database.BeginTransaction():它是在一个已存在的DbContext上下文中对于我们去启动和完成transactions的一种简单方式,它允许多个操作组合存在在相同的transaction中,所以要么提交要么全部作为一体回滚,同时它也允许我们更加容易的去显示指定transaction的隔离级别。
  • Dtabase.UseTransaction():它允许DbContext上下文使用一个在EF实体框架之外启动的transaction。

2默认事务

当我们调用SaveChanges方法来执行增、删、改时其操作内部都用一个transaction包裹着(自动完成的)。如下图,当添加数据时:

EF 事务(转载)

  • 对于上下文中的 ExecuteSqlCommand() 方法默认情况下也是用transaction包裹着命令(Command),其有重载我们可以显示指定执行事务还是不确定执行事务。
  • 在此上两种情况下,事务的隔离级别是数据库提供者认为的默认设置的任何隔离级别,例如在SQL Server上默认是READ COMMITED(读提交)。
  • EF对于任何查询都不会用transaction来进行包裹。

  在EF 6.0版本以上,EF一直保持数据库连接打开,因为要启动一个transaction必须是在数据库连接打开的前提下,同时这也就意味着我们执行多个操作在一个transaction的唯一方式是要么使用 TransactionScope 要么使用 ObjectContext.Connection 属性并且启动调用Open()方法以及BeginTransaction()方法直接返回EntityConnection对象。如果你在底层数据库连接上启动了transaction,再调用API连接数据库可能会失败。

3同一上下文中使用transaction

Database.BeginTransaction有两种重载——一种是显示指定隔离级别,一种是无参数使用来自于底层数据库提供的默认隔离级别,两种都是返回一个DbContextTransaction对象,该对象提供了事务提交(Commint)以及回滚(RollBack)方法直接表现在底层数据库上的事务提交以及事务回滚上。

DbContextTransaction一旦被提交或者回滚就会被Disposed,所以我们使用它的简单的方式就是使用using(){}语法,当using构造块完成时会自动调用Dispose()方法。

根据上述我们现在通过两个步骤来对学生进行操作,并在同一transaction上提交。如下:

EF 事务(转载)
            using (var ctx = new EntityDbContext())
{ using (var ctxTransaction = ctx.Database.BeginTransaction())
{ try
{
ctx.Database.Log = Console.WriteLine; ctx.Database.ExecuteSqlCommand("update student set name='xpy0929'"); var list = ctx.Set<Student>().Where(p => p.Name == "xpy0929").ToList(); list.ForEach(d =>
{ d.Name = "xpy0928"; }); ctx.SaveChanges(); ctxTransaction.Commit();
}
catch (Exception)
{
ctxTransaction.Rollback();
} }
}
EF 事务(转载)

我们通过控制台输出SQL日志查看提交事务成功如下:

EF 事务(转载)

【注意】 要开始一个事务必须保持底层数据库连接是打开的,如果数据库不总是打开的我们可以通过 BeginTransaction() 方法将打开数据库连接,如果 DbContextTransaction 打开了数据库,当调用Disposed()方法时将会关闭数据库连接。

4注意事项

1一定要用using包裹,保证每次上下文会新建和释放,这个上下文不可与其它方法共用。

2当用EF上下文中的 Database.ExecuteSqlCommand 方法来对数据库进行如下操作时

EF 事务(转载)
            using (var ctx = new EntityDbContext())
{ var sqlCommand = String.Format("ALTER DATABASE {0} SET SINGLE_USER WITH ROLLBACK IMMEDIATE", "DBConnectionString");
ctx.Database.ExecuteSqlCommand(sqlCommand); }
EF 事务(转载)

此时将会报错如下:

EF 事务(转载)

上述已经讲过此方法会被Transaction包裹着,所以导致出错,但是此方法有重载,我们进行如下设置即可

 ctx.Database.ExecuteSqlCommand(TransactionalBehavior.DoNotEnsureTransaction,sqlCommand);

5将一个已存在的事务添加到上下文中

有时候我们可能需要事务的作用域更加广一点,当然是在同一数据库上但是是在EF之外完全进行操作。基于此,此时我们必须手动打开底层的数据库连接来启动事务,同时通知EF使用我们手动打开的连接来使现有的事务连接在此连接上,这样就达到了在EF之外使用事务的目的。

为了实现上述在EF之外使用事务我们必须在DbContext上下文中的派生类的构造器中关闭自身的连接而使用我们传入的连接。

第一步

上下文中关闭EF连接使用底层连接。

代码如下:

  public EntityDbContext(DbConnection con)
: base(con, contextOwnsConnection: false)
{ }

第二步

启动Transcation(如果我们想避免默认设置我们可以手动设置隔离级别),通知EF一个已存在的Transaction已经在我们手动的设置的底层连接上启动。

EF 事务(转载)
            using (var con = new SqlConnection("ConnectionString"))
{
using (var SqlTransaction = con.BeginTransaction())
{
using (var ctx = new EntityDbContext(con))
{
}
}
}
EF 事务(转载)

第三步

因为此时是在EF实体框架外部执行事务,此时则需要用到上述所讲的 Database.UseTransaction 将我们的事务对象传递进去。

 ctx.Database.UseTransaction(SqlTransaction);

此时我们将能通过SqlConnection实例来*执行数据库操作或者说是在上下文中,执行的所有操作都是在一个Transaction上,而我们只负责提交和回滚事务并调用Dispose方法以及关闭数据库连接即可。

至此给出完整代码如下:

EF 事务(转载)
            using (var con = new SqlConnection("ConnectionString"))
{
con.Open();
using (var SqlTransaction = con.BeginTransaction())
{
try
{
var sqlCommand = new SqlCommand();
sqlCommand.Connection = con;
sqlCommand.Transaction = SqlTransaction;
sqlCommand.CommandText =
@"update student set name = 'xpy0929'";
sqlCommand.ExecuteNonQuery(); using (var ctx = new EntityDbContext(con))
{ ctx.Database.UseTransaction(SqlTransaction); var list = ctx.Set<Student>().Where(d => d.Name == "xpy0929").ToList(); list.ForEach(d => {
d.Name = "xpy0928";
}); ctx.SaveChanges(); } SqlTransaction.Commit();
}
catch (Exception)
{
SqlTransaction.Rollback(); }
} }
EF 事务(转载)

【注意】你可以设置  ctx.Database.UseTransaction(null); 为空来清除当前EF中的事务,如果你这样做了,那么此时EF既不会提交事务也不会回滚现有的事务,除非你清楚这是你想做的 ,否则请谨慎使用。

6 TransactionScope Transactions

在msdn上对 TransactionScope 类定义为是:类中的代码称为事务性代码。

我们将上述代码包含在如下代码中,则此作用域里的代码为事务性代码

            using ( var scope = new TransactionScope(TransactionScopeOption.Required))
{ }

【注意】此时SqlConnection和EF实体框架都使用 TransactionScope  ,因此此时将被会一起提交。

在.NET 4.5.1中 TransactionScope  能够和异步方法一起使用通过TransactionScopeAsyncFlowOption的枚举来启动。

通过如下实现:

using (var scope = new TransactionScope(TransactionScopeAsyncFlowOption.Enabled))
{}

接着就是将数据库连接的打开方法(Open)、查询方法(ExecuteNonQuery)、以及上下文中保存的方法(SaveChanges)都换为对应的异步方法(OpenAsync)、(ExecuteNonQueryAsync)以及(SaveChangesAsync)即可

EF 事务(转载)的更多相关文章

  1. 分享我们项目中基于EF事务机制的架构 【转载】

    http://www.cnblogs.com/leotsai/p/how-to-use-entity-framework-transaction-scope.html 写在前面: 1. 本文中单元测试 ...

  2. 分享我们项目中基于EF事务机制的架构

    写在前面: 1. 本文中单元测试用到的数据库,在执行测试之前,会被清空,即使用空数据库. 2. 本文中的单元测试都是正确通过的. 要理解EF的事务机制,首先要理解这2个类:TransactionSco ...

  3. EF 事务

    http://yanwushu.byethost7.com/?p=87 1. EF对事务进行了封装:context的saveChange()是有事务性的. 2. 依赖多个不同的Context的操作(即 ...

  4. EF 事务&lpar;非分布式事务&rpar;

    在EF 中怎么使用事务? 这个问题纠结了我好久,直到有人跟我一起讨论,我和同事一起讨论查资料. 查的好多资料都是使用 TransactionScope,用 TransactionScope 可处理分布 ...

  5. EF事务嵌套

    EF中采用的是数据上下文DbContext,当针对数据库的所有操作共用一个数据上下文的时候,会使用同一个连接对象,因此连接打开一次,最后Save的时候关闭连接,避免了频繁的创建连接对象打开关闭,这在一 ...

  6. MySql EF事务using不会自动 Rollback的bug

    EF to MySql一般都是用using最后Commit,一直以为最后没Commit,当using调用Dispose会自动Rollback,没想到这儿有个坑,mysql有个bug并不会Rollbac ...

  7. 第六章 springboot &plus; 事务&lpar;转载&rpar;

    本篇博客转发自:http://www.cnblogs.com/java-zhao/p/5350106.html 在实际开发中,其实很少会用到事务,一般情况下事务用的比较多的是在金钱计算方面. myba ...

  8. 使用Atomikos Transactions Essentials实现多数据源JTA分布式事务--转载

    原文:http://www.ite/topic/122700 9.17 update:使用NonXADataSourceBean. Mysql在5.0版本和Connecter/J5.0版本后提供了XA ...

  9. EF事务封装

    public class EFTransaction:ITransaction { DbContextTransaction originalTransaction = null; MyDbConte ...

随机推荐

  1. Resharper的配置和使用

    一:Reshaper简介 Reshaper是C#开发IDE工具Visual Studio的一款第三方插件,Reshaper让 VS 变得更强大.优势是:它提供了一些在 VS 基础上更方便于程序员开发的 ...

  2. python&lowbar;射门小游戏

    import random def shoot(fs = 0,i = 0,j = 0): while i < 5: print("<<<<<<&lt ...

  3. 用freemarker生产静态页面

    FreeMarker概述 * FreeMarker是一个模板引擎,一个基于模板生成文本输出的通用工具,使用纯Java编写     * Template + data model = output    ...

  4. word2010插入奇数页 使奇偶页不同的问题

    word2010版本,设计奇偶页不同时,遇到一个问题,就是在第一章最后插入分节符——奇数页时,会导致整个奇数页都为1.原因:①首先每一章的末尾都应该有分页符或者奇数页等分节符来分开每一章:②点击页码可 ...

  5. Android中ListView滚动时上下边界的那一抹色彩

    后台实现: if (Integer.parseInt(Build.VERSION.SDK) >= 9) { listview.setOverScrollMode(View.OVER_SCROLL ...

  6. VS2012无法创建项目:未找到与约束……匹配的导出

    故障情况:7月10号后用VS2012创建项目时,弹出如下对话框,无法创建新项目: 而后经网络搜索确定是7月10号更新了系统补丁后造成的 解决方案: 1.卸载这两个补丁后重启电脑: 2.到http:// ...

  7. &num;module-django&period;db&period;models

    Models A model is the single, definitive source of information about your data. It contains the esse ...

  8. 简单随笔——如何在gridview的页脚显示信息。。。。

    我是超级大菜鸟...哈哈 先上图看看是不是你需要的 第一步,右击gridview,在事件中,单击RowdataBond事件. 在这之前一定要记得在gridview属性中的ShowFooter设置为“t ...

  9. 实例了解js面向对象的封装和继承等特点

    1.面向对象特点 相比之前按照过程式写法,面向对象有以下几个特点; 1.抽象:抓住核心问题,就是将很多个方法放在一个对象上.对象由属性和方法组成,属性就是我们定义的变量,它是静态的:方法就是行为操作, ...

  10. 关于线程和junit注入失败的问题

    问题: 在使用spring的时候,通常会使用注释@Autowired或@Resource注入java Bean; 但是在碰到线程类和测试类的时候就不支持注入方式了. 定义: 线程类:继承thread或 ...