默认情况下,当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(, )); context.SaveChanges(); context.Database.ExecuteSqlCommand("update Person3 setDescription={0} where Person3Id={1}", "DescriptionModified at " + DateTime.Now.ToShortTimeString(), p.Person3Id);
p.age *= ;
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

EntityFramework 事务处理的更多相关文章

  1. EntityFramework用法探索(八)事务处理

    使用 前文中描述的Retail示例 ,在Customer对象的Mapping中设置Name属性:我们构造一个有效的Customer对象,再构造一个无效的Name属性为空的对象. DomainModel ...

  2. (转)EntityFramework之领域驱动设计实践

    EntityFramework之领域驱动设计实践 - 前言 EntityFramework之领域驱动设计实践 (一):从DataTable到EntityObject EntityFramework之领 ...

  3. .net EntityFramework用法探索系列 1

    EntityFramework用法探索系列 (一)DatabaseFirst (二)CodeFirst (三)CodeFirst流畅API (四)Repository和UnitOfWork (五)引入 ...

  4. EntityFramework 6.x多个上下文迁移实现分布式事务

    前言 自从项目上了.NET Core平台用上了EntityFramework Core就再没碰过EntityFramework 6.x版本,目前而言EntityFramework 6.x是用的最多,无 ...

  5. ASP.NET没有魔法——ASP.NET MVC 与数据库之EntityFramework配置与连接字符串

    前几篇文章中介绍了如何使用Entity Framework来操作数据库,但是对EF的配置.连接字符串的指定仍然存在一些疑问. 本章将对EF的配置进行介绍. EF可以通过两种方式来实现配置,分别是代码方 ...

  6. EntityFramework之领域驱动设计实践

    EntityFramework之领域驱动设计实践 - 前言 EntityFramework之领域驱动设计实践 (一):从DataTable到EntityObject EntityFramework之领 ...

  7. 基于 EntityFramework 的数据库主从读写分离架构(2)- 改进配置和添加事务支持

        回到目录,完整代码请查看(https://github.com/cjw0511/NDF.Infrastructure)中的目录:      src\ NDF.Data.EntityFramew ...

  8. C# 嵌入dll 动软代码生成器基础使用 系统缓存全解析 .NET开发中的事务处理大比拼 C#之数据类型学习 【基于EF Core的Code First模式的DotNetCore快速开发框架】完成对DB First代码生成的支持 基于EF Core的Code First模式的DotNetCore快速开发框架 【懒人有道】在asp.net core中实现程序集注入

    C# 嵌入dll   在很多时候我们在生成C#exe文件时,如果在工程里调用了dll文件时,那么如果不加以处理的话在生成的exe文件运行时需要连同这个dll一起转移,相比于一个单独干净的exe,这种形 ...

  9. ASP.NET开发实战——(十一)ASP.NET MVC 与数据库之EntityFramework配置与连接字符串

    前几篇文章中介绍了如何使用Entity Framework来操作数据库,但是对EF的配置.连接字符串的指定仍然存在一些疑问,EF可以通过两种方式来实现配置,分别是代码方式和配置文件. 本章将通过以下几 ...

随机推荐

  1. Android线程管理之ThreadLocal理解及应用场景

    前言: 最近在学习总结Android的动画效果,当学到Android属性动画的时候大致看了下源代码,里面的AnimationHandler存取使用了ThreadLocal,激起了我很大的好奇心以及兴趣 ...

  2. SQL Server-聚焦查询计划Stream Aggregate VS Hash Match Aggregate(二十)

    前言 之前系列中在查询计划中一直出现Stream Aggregate,当时也只是做了基本了解,对于查询计划中出现的操作,我们都需要去详细研究下,只有这样才能对查询计划执行的每一步操作都了如指掌,所以才 ...

  3. Spring Enable annotation – writing a custom Enable annotation

    原文地址:https://www.javacodegeeks.com/2015/04/spring-enable-annotation-writing-a-custom-enable-annotati ...

  4. 一个表缺失索引发的CPU资源瓶颈案例

    背景 近几日,公司的应用团队反应业务系统突然变慢了,之前是一直比较正常.后与业务部门沟通了解详情,得知最近生意比较好,同时也在做大的促销活动,使得业务数据处理的量出现较大的增长,最终系统在处理时出现瓶 ...

  5. Velocity初探小结--velocity使用语法详解

    做java开发的朋友一般对JSP是比较熟悉的,大部分人第一次学习开发View层都是使用JSP来进行页面渲染的,我们都知道JSP是可以嵌入java代码的,在远古时代,java程序员甚至在一个jsp页面上 ...

  6. MySQL 系列(二) 你不知道的数据库操作

    第一篇:MySQL 系列(一) 生产标准线上环境安装配置案例及棘手问题解决 第二篇:MySQL 系列(二) 你不知道的数据库操作 本章内容: 查看\创建\使用\删除 数据库 用户管理及授权实战 局域网 ...

  7. i++、++i 、i--、--i

    总结: i++ 先用后加, ++i先加后用: i--先用后减, --i先减后用: //int i = 1; //Console.WriteLine(i);//1 //Console.WriteLine ...

  8. BZOJ 1391: [Ceoi2008]order [最小割]

    1391: [Ceoi2008]order Time Limit: 10 Sec  Memory Limit: 64 MBSubmit: 1509  Solved: 460[Submit][Statu ...

  9. NYOJ 954

    首先观察: 2! = 2×1                 = (2)10     = (10)2,        则第一个1是第2位,2!有1个质因数23! = 3×2×1             ...

  10. Microsoft SQL Server中的事务与并发详解

    本篇索引: 1.事务 2.锁定和阻塞 3.隔离级别 4.死锁 一.事务 1.1 事务的概念 事务是作为单个工作单元而执行的一系列操作,比如查询和修改数据等. 事务是数据库并发控制的基本单位,一条或者一 ...