分享我们项目中基于EF事务机制的架构 【转载】
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事务机制的架构 【转载】的更多相关文章
- 分享我们项目中基于EF事务机制的架构
写在前面: 1. 本文中单元测试用到的数据库,在执行测试之前,会被清空,即使用空数据库. 2. 本文中的单元测试都是正确通过的. 要理解EF的事务机制,首先要理解这2个类:TransactionSco ...
- [翻译 EF Core in Action 1.10] 应该在项目中使用EF Core吗?
Entity Framework Core in Action Entityframework Core in action是 Jon P smith 所著的关于Entityframework Cor ...
- 在项目中部署redis的读写分离架构(包含节点间认证口令)
#### 在项目中部署redis的读写分离架构(包含节点间认证口令) ##### 1.配置过程 --- 1.此前就是已经将redis在系统中已经安装好了,redis utils目录下,有个redis ...
- 采用EntLib5.0(Unity+Interception+Caching)实现项目中可用的Caching机制
看了园子里很多介绍Caching的文章,多数都只介绍基本机制,对于Cache更新和依赖部分,更是只简单的实现ICacheItemRefreshAction接口,这在实际项目中是远远不够的.实际项目中, ...
- visual studio 项目中使用EF创建的数据库,后续更新数据库操作(生产已经部署,不能删除数据库重新创建)
情景:SharePoint项目(其他类型的项目道理也一样),数据库是用EF(版本:6.0.0.0)创建的,生产环境已经使用,所以后续修改数据库,只能通过更新来实现. 下面是具体的操作方式: 1.vis ...
- 关于项目中的DAL数据接入层架构设计
摘要:项目中对关系型数据库的接入再寻常不过,也有海量的ORM工具可供选择,一个一般性的DAL数据接入层的结构却大同小异,这里就分享一下使用Hibernate.Spring.Hessian这三大工具对D ...
- 实际项目中遇到EF实体类的操作问题及操作方法
之前一直做ASP,都是直接写数据库操作语句,但是现在使用linq或者EF了,具体数据库操作不会了,遇到几个问题,然后经过查找资料解决了,记录一下. 一.遇到序列化问题 遇到循环引用问题,我的项目是一个 ...
- 在Blazor Server 项目中使用 EF Core Sqlite
按照教程创建了一个 Blazor Server 项目 教程地址: https://docs.microsoft.com/zh-cn/aspnet/core/tutorials/build-a-blaz ...
- vue项目中基于D3.js实现桑基图功能
前端实现数据可视化的方案有很多种,以前都是使用百度的echarts,使用起来很方便,直接按照特定的数据格式输入,就能实现相应的效果,虽然使用方便,但是缺点就是无法自定义一些事件操作,可自由发挥的功能很 ...
随机推荐
- elasticsearch简介
elasticsearch 摘要: 1 es是一个分布式全文搜索引擎.特定是:无中心化,实时,扩展性强. 2. es有几个好的概念或者特点:(1)cluster 集群无中心化.(2)shards.分片 ...
- APUE读书笔记:关于sigsuspend
sigsuspend是一个原子操作,为了防止信号丢失而存在的,具体含义看下函数原型. int sigsuspend(const sigset_t *mask); 先忽略参数,sigsuspend完成的 ...
- Linux KVM 安装配置
--------------------------一.前言二.环境三.安装与配置四.创建kvm虚拟机 一.前言 KVM,即Kernel-based Virtual Machine的简称,是一个开源的 ...
- 关于ckeditor过滤掉html样式标签之我见
1.CKEDITOR编辑器属性可以通过修改/ckeditor/config.js文件来控制 //标签过滤默认是开启的,默认会过了<style>样式标签设置为true可关闭过滤config. ...
- pci 相关资料
1.http://www.cnblogs.com/image-eye/archive/2012/02/15/2352699.html
- java问题诊断
http://techblog.youdao.com/?p=961 http://linuxtools-rst.readthedocs.org/zh_CN/latest/advance/03_opti ...
- Django 分页功能
Django 分页功能比较强大,这边是结合官网的内容写的可以参考 https://docs.djangoproject.com/en/1.9/topics/pagination/ 分页命令行练习案列 ...
- MySQL与Oracle的区别
1.语法上的区别 变量类型定义.IN OUT的位置.变量定义的位置.游标的位置.异常的位置: 2.MySQL没有 return 关键字,采用leave label的方式结束循环或跳出存储 3.异常处 ...
- java操作oracle的blob,clob数据
一.区别和定义 LONG: 可变长的字符串数据,最长2G,LONG具有VARCHAR2列的特性,可以存储长文本一个表中最多一个LONG列 LONG RAW: 可变长二进制数据,最长2G CLOB: ...
- php 数据库并发处理
在并行系统中并发问题永远不可忽视.尽管PHP语言原生没有提供多线程机制,那并不意味着所有的操作都是线程安全的.尤其是在操作诸如订单.支付等业务系统中,更需要注意操作数据库的并发问题. 接下来我通过一个 ...