Unit Of Work--工作单元(一)
简介
最近忙着新项目的架构,已经有一段时间没有更新博客了,一直考虑着要写些什么,直到有一天跟朋友谈起他们公司开发数据层遇到的一些问题时,我想应该分享一些项目中使用的数据访问模式。
虽然最近一直都在使用Go语言开发数据服务器,但是本篇文章用到的语言仍然是C#,文章内提供的代码仅仅是分享如何使用工作单元,至于如何将这个模式引入到项目中去,就需要各位自己去实现了,毕竟每个项目都是不一样的,需要根据项目具体的环境来进行组合。
本篇文章包括以下内容:
- 什么是工作单元
- 基于ADO.NET的实现
- 总结
什么是工作单元
该模式用来维护一个由已经被业务事务修改(CRUD除了R)的业务对象组成的列表并负责协调这些修改的持久化工作以及所有标记的并发问题。
在web应用中,由于每个用户的请求都是属于不同线程的,需要保持每次请求的所有数据操作都成功的情况下提交数据,只要有一个失败的操作,则会对用户的此次请求的所有操作进行回滚,以确保用户操作的数据始终处于有效的状态。
需要更详细的了解,可以查看此篇文章。
基于ADO.NET的实现
在不使用任何数据层框架,仅仅使用ADO.NET的情况下,一般流程的方式如下:
- 实例化IDbConnection
- 然后实例化IDbCommand
- 设置IDbCommand的Text和Parameters
- 执行IDbCommand.ExecuteNoQuery
- 释放IDbCommand、IDbConnection
一般情况下,我们会给每个数据库表创建对应的数据库交互类并提供CRUD方法,除了R以外,其他的方法都会实现以上的流程。
然而如果用户一次请求会进行多次CUD操作的情况下,只能在用户开始进行数据操作之前使用TransactionScope将多次操作包裹在内,这样实现相对麻烦的。
其实我们可以将用户进行的CUD的SQL语句与参数现在保存起来,到最后再一并进行提交,有点类似存储过程的样子,这其实就是工作单元模式了,首先创建一个用来存储SQL语句和参数的类,代码如下:
class SQLEntity
{
private string m_SQL = null;
public string SQL
{
get { return m_SQL; }
} private IDataParameter[] m_Parameters = null;
public IDataParameter[] Parameters
{
get { return m_Parameters; }
} public Entity(string sql, params IDataParameter[] parameters)
{
this.m_SQL = sql;
this.m_Parameters = parameters;
}
}
如果将所有CUD的操作都放在一个List<SQLEntity>内,在需要提交的时候只需要遍历List<SQLEntity>内的元素,并通过重复开始的流程就行(这里需要稍微重构一下),代码如下:
class SQLUnitOfWork
{
private IDbConnection m_connection = null;
private List m_operations = new List(); public SQLUnitOfWork(IDbConnection connection)
{
this.m_connection = connection;
} public void RegisterAdd(string sql, params IDataParameter[] parameters)
{
this.m_operations.Add(new SQLEntity(sql, parameters));
} public void RegisterSave(string sql, params IDataParameter[] parameters)
{
this.m_operations.Add(new SQLEntity(sql, parameters));
} public void RegisterRemove(string sql, params IDataParameter[] parameters)
{
this.m_operations.Add(new SQLEntity(sql, parameters));
} public void Commit()
{
using (IDbTransaction trans = this.m_connection.BeginTransaction())
{
try
{
using (IDbCommand cmd = this.m_connection.CreateCommand())
{
cmd.Transaction = trans;
cmd.CommandType = CommandType.Text;
this.ExecuteQueryBy(cmd);
}
trans.Commit();
}
catch (Exception ex)
{
trans.Rollback();
}
}
} private void ExecuteQueryBy(IDbCommand cmd)
{
foreach (var entity in this.m_operations)
{
cmd.CommandText = entity.SQL;
cmd.Parameters.Clear();
foreach (var parameter in entity.Parameters)
{
cmd.Parameters.Add(parameter);
}
cmd.ExecuteNonQuery();
}
this.m_operations.Clear();
}
}
有了以上的SQLUnitOfWork,我们的数据库类在调用CUD方法的时候,就只要调用相应RegisterXXX方法了,数据层实现代码如下:
class SchoolRepository
{
private SQLUnitOfWork m_uow = null; public SchoolRepository(SQLUnitOfWork uow)
{
this.m_uow = uow;
} public void Add(School school)
{
this.m_uow.RegisterAdd("insert school values(@id, @name)", new IDbDataParameter[]{
new SqlParameter("@id", school.Id),
new SqlParameter("@name", school.Name)
});
} public void Save(School school)
{
this.m_uow.RegisterSave("update school set name = @name where id = @id", new IDbDataParameter[]{
new SqlParameter("@id", school.Id),
new SqlParameter("@name", school.Name)
});
} public void Remove(School school)
{
this.m_uow.RegisterRemove("delete from school where id = @id", new IDbDataParameter[]{
new SqlParameter("id", school.Id)
});
}
} class StudentRepository
{
//代码类似,因此省略
}
有了以上的准备,再使用以下的代码来看看工作单元的效果,代码如下:
SQLUnitOfWork uow = new SQLUnitOfWork(connection);
SchoolRepository schoolRepositry = new SchoolRepository(uow);
StudentRepository studentRepository = new StudentRepository(uow); School school = new School
{
Id = Guid.NewGuid().ToString(),
Name = "一中",
};
schoolRepositry.Add(school); for (int i = 0; i < 7; i++)
{
Student student = new Student
{
Id = Guid.NewGuid().ToString(),
Name = string.Format("学生{0}号", i),
Age = 7 + i,
SchoolId = school.Id
};
studentRepository.Add(student);
} school.Name = "二中";
schoolRepositry.Save(school); uow.Commit();
接着会看到数据库中会看到图中的数据,如图:

总结
这样就完成了基于ADO.NET的简单工作单元实现了,可能有些人会有疑问,跟其他人实现的工作单元有很多不同的地方,这是因为该版本只是一个大致思路的实现,并没有跟其他框架、库的结合,为了能使其他人理解工作单元的原理,因此实现相对比较简单。
由于模式是一种解决方案,一种思路,每个项目的环境、功能、结构都不一样,因此实现的方式会有不同。对于模式不能死记硬背,要理解其中的原理,可以通过自我实践或者参考他人的代码来实现,如果每个项目都是照抄模式的话,那么就失去了它该有的作用了。
在下一篇文章中,我会重构以上的代码,实现以兼容ADO.NET和ORM框架的工作单元,那么文章就到这里了,如果有问题和疑问欢迎留言,代码仅供参考请勿应用到实际项目中,谢谢。
Unit Of Work--工作单元(一)的更多相关文章
- ABP(现代ASP.NET样板开发框架)系列之12、ABP领域层——工作单元(Unit Of work)
点这里进入ABP系列文章总目录 基于DDD的现代ASP.NET开发框架--ABP系列之12.ABP领域层——工作单元(Unit Of work) ABP是“ASP.NET Boilerplate Pr ...
- ABP领域层——工作单元(Unit Of work)
ABP领域层——工作单元(Unit Of work) 点这里进入ABP系列文章总目录 基于DDD的现代ASP.NET开发框架--ABP系列之12.ABP领域层——工作单元(Unit Of work) ...
- 解析ABP框架中的事务处理和工作单元,ABP事务处理
通用连接和事务管理方法连接和事务管理是使用数据库的应用程序最重要的概念之一.当你开启一个数据库连接,什么时候开始事务,如何释放连接...诸如此类的. 正如大家都知道的,.Net使用连接池(connec ...
- [Abp 源码分析]六、工作单元的实现
0.简介 在 Abp 框架内部实现了工作单元,在这里讲解一下,什么是工作单元? Unit Of Work(工作单元)模式用来维护一个由已经被业务事物修改(增加.删除或更新)的业务对象组成的列表.Uni ...
- [.NET领域驱动设计实战系列]专题四:前期准备之工作单元模式(Unit Of Work)
一.前言 在前一专题中介绍了规约模式的实现,然后在仓储实现中,经常会涉及工作单元模式的实现.然而,在我的网上书店案例中也将引入工作单元模式,所以本专题将详细介绍下该模式,为后面案例的实现做一个铺垫. ...
- 换个角度说工作单元(Unit Of Work):创建、持有与API调用
看到一些工作单元的介绍,有两种感觉,第一种是很学院,说了等于没说,我估计很多都是没有自己引入到实际的项目中去,第二种是告诉我一种结果,说这就是工作单元,但是没说为什么要这么使用.所以,本篇想要探讨的是 ...
- 工作单元(Unit of Work)
维护受业务事务影响的对象列表,并协调变化的写入和并发问题的解决. 从DB中存取Data时,必须记录增删改动作,以将对DB有影响的数据写会到DB中去. 如果在每次修改对象模型时就对DB进行相应的修改,会 ...
- ABP理论学习之工作单元(Unit of Work)
返回总目录 本篇目录 公共连接和事务管理方法 ABP中的连接和事务管理 仓储类 应用服务 工作单元 工作单元详解 关闭工作单元 非事务的工作单元 工作单元方法调用其它 工作单元作用域 自动保存 IRe ...
- 基于DDD的.NET开发框架 - ABP工作单元(Unit of Work)
返回ABP系列 ABP是“ASP.NET Boilerplate Project (ASP.NET样板项目)”的简称. ASP.NET Boilerplate是一个用最佳实践和流行技术开发现代WEB应 ...
- 【.Net设计模式系列】工作单元(Unit Of Work)模式 ( 二 )
回顾 在上一篇博客[.Net设计模式系列]仓储(Repository)模式 ( 一 ) 中,通过各位兄台的评论中,可以看出在设计上还有很多的问题,在这里特别感谢 @横竖都溢 @ 浮云飞梦 2位兄台对博 ...
随机推荐
- iOS开发之静态库(一)—— 基本概念
在项目开发过程中,经常出现优秀代码重用现象,又或者提供给第三方功能模块却又不想让其看到源代码,这些时候,通常的做法是将代码封装成库或者框架,这些在Windows编程或Linux编程中非常容易实现的过程 ...
- Django网站管理、后台、模型(Admin)
1. 启动wampserver 2. 新建一个名为mysite的项目django-admin.py startproject mysite 3. 新建一个叫做blog的appcd mysitepyth ...
- 详解Bootstrap缩略图组件及警示框组件
缩略图组件 缩略图在网站中最常用的就是产品列表页面,一行显示几张图片,有的在图片底下带有标题.描述内容.按钮等信息.bootstrap框架将这部分独立成一个模块组件,通过类名.thumbnail配合b ...
- iptables防火墙原理详解
1. netfilter与iptables Netfilter是由Rusty Russell提出的Linux 2.4内核防火墙框架,该框架既简洁又灵活,可实现安全策略应用中的许多功能,如数据包过滤.数 ...
- 關於imagick不得不說的一些事
PHP建圖通常都用GD庫,因為是內置的不需要在服務器上額外安裝插件,所以用起來比較省心,但是如果你的程序主要的功能就是處理圖像,那麼就不建議用GD了,因為GD不但低效能而且能力也比較弱,佔用的系統資源 ...
- 解决真机调试时Eclipse DDMS上打不开/data目录的问题
一般真机调试时DDMS里面的File Explorer是不能打开/data 目录的,不过也很容易解决. 1.首先手机要root.这个很简单,网上一大堆资料和软件. 2.仅仅root之后还不行,下载一个 ...
- HTML解析组件HtmlAgilityPack使用
HtmlAgilityPack是一个开源的解析HTML元素的类库,最大的特点是可以通过XPath来解析HMTL,如果您以前用C#操作过XML,那么使用起HtmlAgilityPack也会得心应手.目前 ...
- 画之国 Le tableau (2011)
在佛斯特的肚子里,靠近幽门的地方,两只阿米巴原虫快乐地生活着.他们的日子过得很舒服,从来没饿过肚子,而且根本用不着干活:因为他们就是所谓的寄生虫.这两个好朋友相处得很愉快,但时不时也会争论不休,因为他 ...
- Swift 必备开发库 (高级篇)
1.CryptoSwift swift加密库, 支持md5,sha1,sha224,sha256... github地址: https://github.com/krzyzanowskim/Crypt ...
- Navi.Soft30.框架.Mobile.开发手册
1概述 1.1应用场景 互联网的发展,使用基于Web的软件异军突起,目前占据着相当大的市场份额,而手机,平板电脑等移动端设备的频繁使用,使移动端的软件快速发展,逐步有超越Web软件的趋势 移动软件中, ...