http://www.cnblogs.com/leotsai/p/how-to-use-entity-framework-transaction-scope.html

写在前面:

1. 本文中单元测试用到的数据库,在执行测试之前,会被清空,即使用空数据库。

2. 本文中的单元测试都是正确通过的。

要理解EF的事务机制,首先要理解这2个类:TransactionScope和DbContext。

DbContext是我们的数据库,通常我们会建一个类MyProjectDbContext继承自DbContext,里面包含所有的数据库表。这个类相当于定义了一个完整的数据库。

下面通过一些单元测试来看看这2个类是如何工作的。

 [Test]
public void Can_Rollback_On_Errors_In_Different_Context()
{
var user1 = Mock.Users.Random();
var user2 = Mock.Users.Random();
user2.FirstName = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
var userCount = ;
try
{
using (var scope = new TransactionScope())
{
using (var db = new MyProjectDbContext())
{
db.Users.Add(user1);
db.SaveChanges();
userCount = db.Users.Count();
}
using (var db = new MyProjectDbContext())
{
db.Users.Add(user2);
db.SaveChanges();//will throw exception
}
scope.Complete();
}
}
catch(Exception)
{ }
Assert.AreEqual(, userCount);
using (var db = new MyProjectDbContext())
{
Assert.AreEqual(, db.Users.Count());
}
}

注意第一个assert,userCount是等于1的,也就是说第一个db.SaveChanges()是顺利执行了的。但是看看第二个assert,数据库里面却没有user记录。这就是使用TransactionScope得到的真正的事务机制。

再看一个测试:

 [Test]
public void Cannot_Rollback_Without_Scope()
{
var user1 = Mock.Users.Random();
var user2 = Mock.Users.Random();
user2.FirstName = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
var userCount = ;
try
{
using (var db = new MyProjectDbContext())
{
db.Users.Add(user1);
db.SaveChanges();
userCount = db.Users.Count();
}
using (var db = new MyProjectDbContext())
{
db.Users.Add(user2);
db.SaveChanges();//will throw exception
}
}
catch (Exception)
{ }
Assert.AreEqual(, userCount);
using (var db = new MyProjectDbContext())
{
Assert.AreEqual(, db.Users.Count());
}
}

这个测试跟上面的测试差不多,唯一的区别就是没有使用TransactionScope把两个DbContext包起来。于是每个DbContext成为独立的事务。

再来看一个测试:

 [Test]
public void Shouldnot_SaveToDB_As_ScopeNotComitted()
{
var user1 = Mock.Users.Random();
var userCount = ;
try
{
using (var scope = new TransactionScope())
{
using (var db = new MyProjectDbContext())
{
db.Users.Add(user1);
db.SaveChanges();
userCount = db.Users.Count();
}
//scope.Complete();
}
}
catch (Exception)
{ }
Assert.AreEqual(, userCount);
using (var db = new MyProjectDbContext())
{
Assert.AreEqual(, db.Users.Count());
}
}

}

这个测试表明,一旦DbContext被TransactionScope包起来之后,那么scope必须要调用scope.Complete()才能将数据更新到数据库。

基于上面的这些知识,我们可以很容易为EF搭建支持真正事务的框架。下面我简单介绍下我们的项目架构(EF CodeFirst, MVC)。

基于EF事务机制的架构

Domain层:

定义数据实体类,即数据库中的表。定义继承自DbContext的MyProjectDbContext。

Service层:

主要用于封装所有对数据库的访问。例子代码如下:

 public List<User> GetAllUsers()
{
using (var db = new MyProjectDbContext())
{
return db.Users.ToList();
}
}

上面这段代码中注意要使用using,否则DbContext的延迟加载功能会在controller层被调用。加了using之后,可以避免在controller层对数据库的直接访问。

Controller层:

调用service层的代码从数据库中得到数据,返回给UI。例子:

 public ActionResult GetAllUsers()
{
var users = IoC.GetService<IUserService>().GetAll();
return View(users);
}

同时将UI传回来的数据更新到数据库,这时如果需要调用多个service来更新数据库,那么就需要用到事务。例子:

 public ActionResult DeleteUser(int userId)
{
try
{
using (var scope = new TransactionScope())
{
IoC.GetService<IUserService>().DeleteLogs(userId);
IoC.GetService<IUserService>().DeleteUser(userId);
scope.Complete();
return View();
}
}
catch(Exception)
{ }
return View();
}

通常情况下,我们会在MyControllerBase里面加一个 ActionResult TryScope(Action action)的方法,这样在子类里面就可以不用写try-catch了。

分享我们项目中基于EF事务机制的架构 【转载】的更多相关文章

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

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

  2. [翻译 EF Core in Action 1.10] 应该在项目中使用EF Core吗?

    Entity Framework Core in Action Entityframework Core in action是 Jon P smith 所著的关于Entityframework Cor ...

  3. 在项目中部署redis的读写分离架构(包含节点间认证口令)

    #### 在项目中部署redis的读写分离架构(包含节点间认证口令) ##### 1.配置过程 ---  1.此前就是已经将redis在系统中已经安装好了,redis utils目录下,有个redis ...

  4. 采用EntLib5.0(Unity+Interception+Caching)实现项目中可用的Caching机制

    看了园子里很多介绍Caching的文章,多数都只介绍基本机制,对于Cache更新和依赖部分,更是只简单的实现ICacheItemRefreshAction接口,这在实际项目中是远远不够的.实际项目中, ...

  5. visual studio 项目中使用EF创建的数据库,后续更新数据库操作(生产已经部署,不能删除数据库重新创建)

    情景:SharePoint项目(其他类型的项目道理也一样),数据库是用EF(版本:6.0.0.0)创建的,生产环境已经使用,所以后续修改数据库,只能通过更新来实现. 下面是具体的操作方式: 1.vis ...

  6. 关于项目中的DAL数据接入层架构设计

    摘要:项目中对关系型数据库的接入再寻常不过,也有海量的ORM工具可供选择,一个一般性的DAL数据接入层的结构却大同小异,这里就分享一下使用Hibernate.Spring.Hessian这三大工具对D ...

  7. 实际项目中遇到EF实体类的操作问题及操作方法

    之前一直做ASP,都是直接写数据库操作语句,但是现在使用linq或者EF了,具体数据库操作不会了,遇到几个问题,然后经过查找资料解决了,记录一下. 一.遇到序列化问题 遇到循环引用问题,我的项目是一个 ...

  8. 在Blazor Server 项目中使用 EF Core Sqlite

    按照教程创建了一个 Blazor Server 项目 教程地址: https://docs.microsoft.com/zh-cn/aspnet/core/tutorials/build-a-blaz ...

  9. vue项目中基于D3.js实现桑基图功能

    前端实现数据可视化的方案有很多种,以前都是使用百度的echarts,使用起来很方便,直接按照特定的数据格式输入,就能实现相应的效果,虽然使用方便,但是缺点就是无法自定义一些事件操作,可自由发挥的功能很 ...

随机推荐

  1. 超赞!聊聊WEB APP、HYBRID APP与NATIVE APP的设计差异

    编者按:这3类主流应用你都了解吗?设计师除了要有视觉功夫,对不同形式的APP也应当了然于胸,今天百度的同学写了一篇非常全面的总结,帮你迅速搞定3类主流APP的设计方法,附带一大波避雷针,带你巧妙跳过A ...

  2. Mysql 锁机制

    innodb引擎提供了针对表级锁和行级锁 这个文章说的是行级锁 Lock有两种类型: 1,s-lock(共享锁),拥有该锁的transaction可以对row进行read操作 2,x-lock(排它锁 ...

  3. js获取tr,td内容并排序

    如题 <!DOCTYPE HTML PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.o ...

  4. passwd总结

    1.当前用户是root root用户修改密码 ,直接 passwd[不要输入当前用户密码] 如果修改其他用户密码,需要 passwd 用户名 如: passwd sc 短短的密码,如123也能通过,因 ...

  5. VB 要求对象

    vDoc = WebBrowser1.Document '提示要求对象 Set vDoc = WebBrowser1.Document '正确执行

  6. 转 : 如何用sys as sysdba权限连接数据库进行EXP/IMP

    使用sys as sysdba权限进行EXP/IMP与其它用户稍有不同,详细内容如下(摘自metalink) Applies to: Oracle Server - Enterprise Editio ...

  7. Batch Sort

    Batch Sort time limit per test 2 seconds memory limit per test 256 megabytes input standard input ou ...

  8. POJ 2318 TOYS 叉积

    题目大意:给出一个长方形盒子的左上点,右下点坐标.给出n个隔板的坐标,和m个玩具的坐标,求每个区间内有多少个玩具. 题目思路:利用叉积判断玩具在隔板的左方或右方,并用二分优化查找过程. #includ ...

  9. ZendStudio格式化HTML代码方法及格式化后错位问题修正

    ZendStudio中格式化HTML快捷键:Ctrl+Shift+F 为什么html文件里面的内容格式化完都乱套了? 选 择window菜单->Preferences->Web->H ...

  10. C、C++、java的区别

    经常听到有人在抱怨这个语言哪里哪里 不好,那个语言又是如何的优秀.对于这样 的牢骚,我只是一笑而过. 就我而言,语言只是工具,没有好坏之 分.只要你采用相应的语言,完成对应的工 作,那你的目标就完成了 ...