分享我们项目中基于EF事务机制的架构
写在前面:
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事务机制的架构的更多相关文章
- 分享我们项目中基于EF事务机制的架构 【转载】
http://www.cnblogs.com/leotsai/p/how-to-use-entity-framework-transaction-scope.html 写在前面: 1. 本文中单元测试 ...
- [翻译 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,使用起来很方便,直接按照特定的数据格式输入,就能实现相应的效果,虽然使用方便,但是缺点就是无法自定义一些事件操作,可自由发挥的功能很 ...
随机推荐
- 解决poshytip 表单高度大于屏幕高端 显示问题
Poshy Tip是一款非常友好的信息提示工具,它基于jQuery,当鼠标滑向链接时,会出现一个信息提示条.信息的内容直接可以在HTML里设定也可以是从服务端调用的数据,该插件还提供了很多属性和方法. ...
- MySQL性能优化总结
一.MySQL的主要适用场景 1.Web网站系统 2.日志记录系统 3.数据仓库系统 4.嵌入式系统 二.MySQL架构图: 三.MySQL存储引擎概述 1)MyISAM存储引擎 MyISAM存储引擎 ...
- Kinect开发随笔①——红外扫描仪(Kinect 数据源)
来源于 MVA 的 快速入门:Kinect for Windows v2 开发 的学习随笔 具体内容为上图所示章节内容 章节内全部代码:GitHub地址点我(链接失效,待补档) <Page &l ...
- qtranslate
qtranslate可以帮助用户快速的建立多语言网站平台,qTranslate 插件就是一个功能强大的 WordPress 多语言插件. 它允许用户在配置页添加新的语言.在 URL 结构方面,qTra ...
- Beginning Scala study note(3) Object Orientation in Scala
1. The three principles of OOP are encapsulation(封装性), inheritance(继承性) and polymorphism(多态性). examp ...
- Maven的配置和使用(一)
Selenium已经学习的差不多了,因为之前有开发经验,所以学起来倒是不吃力.在我看来单纯学习selenium这个测试框架是比较简单的,难的是如何理解这个测试框架的构成,如何理解一个自动化测试项目是如 ...
- C# 单例模式
饿汉, 懒汉模式就不说了,下面是IODH模式 static void Main(string[] args) { Singleton s1, s2; s1 = Singleton.getInstanc ...
- ue4 c++学习推荐
我由易到难推荐,不过在此之前还是先看看官方对于VS设置的推荐: https://docs.unrealengine.com/latest/INT/Programming/Development/Vis ...
- 《转》Unity3D研究院编辑器之5.3JSON的序列化
Unity5.3 的一项新功能就是Json的序列化,支持嵌套使用,可以把json字符串转成对象,把对象转成json字符串. using UnityEngine; using UnityEditor; ...
- Linux内核笔记--内存管理之用户态进程内存分配
内核版本:linux-2.6.11 Linux在加载一个可执行程序的时候做了种种复杂的工作,内存分配是其中非常重要的一环,作为一个linux程序员必然会想要知道这个过程到底是怎么样的,内核源码会告诉你 ...