Unit Of Work-工作单元
Unit Of Work-工作单元
阅读目录:
掀起了你的盖头来,让我看你的眼睛,你的眼睛明又亮呀,好像那水波一模样;掀起了你的盖头来,让我看你的脸儿,看看你的脸儿红又圆呀,好像那苹果到秋天。。。
Hi,Unit Of Work,掀起你的盖头来,原来 You are so beautiful !
概念中的理解
Unit Of Work:维护受业务事务影响的对象列表,并协调变化的写入和并发问题的解决。即管理对象的CRUD操作,以及相应的事务与并发问题等。Unit of Work是用来解决领域模型存储和变更工作,而这些数据层业务并不属于领域模型本身具有的。
关于Unit Of Work的更多详情,请查看:http://martinfowler.com/eaaCatalog/unitOfWork.html,Unit Of Work中的“Unit”是单元的意思,知道单元测试的朋友都知道其也包含“Unit”单词,但是是一个意思吗?Unit Test(单元测试)虽然也包含“Unit”这个单词,但是意义并不是一样,单元测试中的“Unit”可以看做是最小单元,比如组装飞机的最小零部件,但是Unit Of Work(工作单元)并非无此,注意后面“Work”单词,意思是可以“工作”的单元,比如一场篮球比赛需要两个队,10名上场球员参与,这样完成的“动作”才会称之为篮球比赛,也就是“工作单元”,一个篮球队或是一个篮球队员并不能完成或称为篮球比赛,但是这个工作的"单元"也只是相对而言,比如上篮动作就只需要一个篮球队员就可以完成,那这个篮球队员就可以看做是“工作单元”。需要注意的是,Unit中可以包含很多“动作”,可以是一个也可以是多个,比如上面的例子,如果“单元”中包含对于多个动作,那这个“单元”中所有的动作都是“内聚”的,脱离这个“单元”这个动作就没有意义了,比如篮球比赛中的一次吹罚,当然这只是字面上理解的意思,也只是我个人的一些看法,希望看到着没有被我忽悠到。
扯了一些不沾边的东西,我们再看一个现实中例子,也最能说明Unit Of Work所包含的意思,就是银行转账操作,包含两个动作:转出方扣钱和转入方加钱,这两个动作要么都完成,要么都不完成,也就是事务操作,完成就Commit(提交),完不成就Rollback(回滚)。
回到Unit Of Work的定义,Unit of Work是用来解决领域模型存储和变更工作,在ORM进行持久化的时候,比如Entity Framework的SaveChanges操作,其实就可以看做是Unit Of Work,也就是定义中所说“用来解决领域模型存储和变更工作”,但是如果项目是基于Entity Framework进行DDD(领域驱动设计)开发设计的,那Entity Framework中的Domain Model就必然包含业务逻辑,这就不符合“而这些数据层业务并不属于领域模型本身具有的”,也就是说Unit Of Work必须独立于Domain Layer(领域层),注意独立的业务是“数据层”业务,并不是业务场景中的“业务”,比如“转账业务”,转出方扣钱和转入方加钱这个业务就属于“数据层业务”,有的人会把Unit Of Work放在Domain Layer(领域层)中,其实是有些不恰当的,应该是放在Infrastructure Layer(基础层)中,但其实也只是相对而言,如果涉及到具体的业务单元模块,具体实现可以放在领域层中。
在DDD(领域驱动设计)开发设计中,Unit Of Work的使用一般会结合Repository(仓储)使用,有关Repository可以参阅dudu的一篇文章:http://www.cnblogs.com/dudu/archive/2011/05/25/repository_pattern.html,文中的解释很清楚直白:
Repository:是一个独立的层,介于领域层与数据映射层(数据访问层)之间。它的存在让领域层感觉不到数据访问层的存在,它提供一个类似集合的接口提供给领域层进行领域对象的访问。Repository是仓库管理员,领域层需要什么东西只需告诉仓库管理员,由仓库管理员把东西拿给它,并不需要知道东西实际放在哪。
Unit Of Work所做的工作可以看做是收集Repository出入库的“商品”,便于一次装车,运输过程中如果没有出现问题,那这车的所有“商品”就安全到达,如果出现问题,那这车的所有“商品”全部打回,这辆车就是“单元”的意思。
关于Repository和Unit Of Work的关系,简单画了个示意图:
代码中的实现
关于Unit Of Work项目中的应用,可以参照dax.net的Byteart Retail项目,本人现在也正在学习中,项目是基于DDD设计实现的,下面是IUnitOfWork的示例代码:

- 1 namespace ByteartRetail.Domain
- 2 {
- 3 /// <summary>
- 4 /// 表示所有集成于该接口的类型都是Unit Of Work的一种实现。
- 5 /// </summary>
- 6 /// <remarks>有关Unit Of Work的详细信息,请参见UnitOfWork模式:http://martinfowler.com/eaaCatalog/unitOfWork.html。
- 7 /// </remarks>
- 8 public interface IUnitOfWork
- 9 {
- 10 /// <summary>
- 11 /// 获得一个<see cref="System.Boolean"/>值,该值表述了当前的Unit Of Work事务是否已被提交。
- 12 /// </summary>
- 13 bool Committed { get; }
- 14 /// <summary>
- 15 /// 提交当前的Unit Of Work事务。
- 16 /// </summary>
- 17 void Commit();
- 18 /// <summary>
- 19 /// 回滚当前的Unit Of Work事务。
- 20 /// </summary>
- 21 void Rollback();
- 22 }
- 23 }

根据UnitOfWork中的概念描述“这些数据层业务并不属于领域模型本身具有的”,所以IUnitOfWork放在Infrastructure Layer(应用层),其实IUnitOfWork的具体管理实现是放在领域层的,但不会放在Domain Model(领域模型)中,具体的数据层业务会结合Repository,也就是说IUnitOfWork会贯彻所有的Repository实现,因为它要对所有仓储的的持久化做统一管理:

- 1 /// <summary>
- 2 /// Represents that the implemented classes are repository contexts.
- 3 /// </summary>
- 4 public interface IRepositoryContext : IUnitOfWork, IDisposable
- 5 {
- 6 /// <summary>
- 7 /// Gets the unique-identifier of the repository context.
- 8 /// </summary>
- 9 Guid ID { get; }
- 10 /// <summary>
- 11 /// Registers a new object to the repository context.
- 12 /// </summary>
- 13 /// <typeparam name="TAggregateRoot">The type of the aggregate root.</typeparam>
- 14 /// <param name="obj">The object to be registered.</param>
- 15 void RegisterNew<TAggregateRoot>(TAggregateRoot obj)
- 16 where TAggregateRoot : class, IAggregateRoot;
- 17 /// <summary>
- 18 /// Registers a modified object to the repository context.
- 19 /// </summary>
- 20 /// <typeparam name="TAggregateRoot">The type of the aggregate root.</typeparam>
- 21 /// <param name="obj">The object to be registered.</param>
- 22 void RegisterModified<TAggregateRoot>(TAggregateRoot obj)
- 23 where TAggregateRoot : class, IAggregateRoot;
- 24 /// <summary>
- 25 /// Registers a deleted object to the repository context.
- 26 /// </summary>
- 27 /// <typeparam name="TAggregateRoot">The type of the aggregate root.</typeparam>
- 28 /// <param name="obj">The object to be registered.</param>
- 29 void RegisterDeleted<TAggregateRoot>(TAggregateRoot obj)
- 30 where TAggregateRoot : class, IAggregateRoot;
- 31 }

UnitOfWork的具体操作会在EntityFrameworkRepositoryContext中完成,并在EntityFrameworkRepository中注册IEntityFrameworkRepositoryContext接口类型映射,EntityFrameworkRepository作用就是在Repository集合中去完成持久化,工作单元的持久化,看下EntityFrameworkRepositoryContext中的示例代码:

- 1 using System.Data.Entity;
- 2 using System.Threading;
- 3
- 4 namespace ByteartRetail.Domain.Repositories.EntityFramework
- 5 {
- 6 public class EntityFrameworkRepositoryContext : RepositoryContext, IEntityFrameworkRepositoryContext
- 7 {
- 8 private readonly ThreadLocal<ByteartRetailDbContext> localCtx = new ThreadLocal<ByteartRetailDbContext>(() => new ByteartRetailDbContext());
- 9
- 10 public override void RegisterDeleted<TAggregateRoot>(TAggregateRoot obj)
- 11 {
- 12 localCtx.Value.Entry<TAggregateRoot>(obj).State = System.Data.EntityState.Deleted;
- 13 Committed = false;
- 14 }
- 15
- 16 public override void RegisterModified<TAggregateRoot>(TAggregateRoot obj)
- 17 {
- 18 localCtx.Value.Entry<TAggregateRoot>(obj).State = System.Data.EntityState.Modified;
- 19 Committed = false;
- 20 }
- 21
- 22 public override void RegisterNew<TAggregateRoot>(TAggregateRoot obj)
- 23 {
- 24 localCtx.Value.Entry<TAggregateRoot>(obj).State = System.Data.EntityState.Added;
- 25 Committed = false;
- 26 }
- 27
- 28 public override void Commit()
- 29 {
- 30 if (!Committed)
- 31 {
- 32 localCtx.Value.SaveChanges();
- 33 Committed = true;
- 34 }
- 35 }
- 36
- 37 public override void Rollback()
- 38 {
- 39 Committed = false;
- 40 }
- 41
- 42 protected override void Dispose(bool disposing)
- 43 {
- 44 if (disposing)
- 45 {
- 46 if (!Committed)
- 47 Commit();
- 48 localCtx.Value.Dispose();
- 49 localCtx.Dispose();
- 50 base.Dispose(disposing);
- 51 }
- 52 }
- 53
- 54 #region IEntityFrameworkRepositoryContext Members
- 55
- 56 public DbContext Context
- 57 {
- 58 get { return localCtx.Value; }
- 59 }
- 60
- 61 #endregion
- 62 }
- 63 }

UnitOfWork的操作会贯彻所有Repository的持久化,在Byteart Retail项目中的领域层,有很多的类和接口关联,比如IEntity、IAggregateRoot、IRepository、IRepositoryContext、Repository、RepositoryContext、EntityFrameworkRepositoryContext等等,用类图表示有时候不太直观,画了一个简单的示例图,方便理解UnitOfWork在DDD中的应用始末:
左半部分:IEntity、IAggreateRoot、IRepository<TAggregateRoot>、Repository<TAggregateRoot>等,可以看做是仓储库,和领域模型相关(存在于领域层),右半部:IUnitOfWork、IRepositoryContext、RepositoryContext、IEntityFrameworkRepositoryContext等,可以看做是仓储的持久化(工作单元),这两者通过EntityFrameworkRepository进行IoC注册对象,完成所有Repository的整个工作单元的协调、管理。
后记
You don't know you're beautiful,that's what makes you beautiful ! -你不知道你是如此的美丽动人,这就是你美丽动人的所在!
如果你觉得本篇文章对你有所帮助,请点击右下部“推荐”,^_^
参考资料:
- http://www.cnblogs.com/OceanEyes/archive/2012/10/29/UnitOfWork--ByEyes.html
- http://www.cnblogs.com/wlflovenet/archive/2011/08/05/EFandMvc9.html
- http://www.cnblogs.com/mecity/archive/2011/07/17/2108508.html
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位兄台对博 ...
随机推荐
- 华为-on练习--重复的字符过滤
称号: 请写一个字符串过滤程序,如果使用多个相同的字符出现在字符串中,字符首次出现在非过滤,. 比方字符串"abacacde"过滤结果为"abcde". 演示样 ...
- Android利用网络编程HttpClient批量上传(两)AsyncTask+HttpClient监测进展情况,并上传
请尊重别人的劳动.转载请注明出处: Android网络编程之使用HttpClient批量上传文件(二)AsyncTask+HttpClient并实现上传进度监听 执行效果图: 我曾在<Andro ...
- Android 滑动界面实现---Scroller类别 从源代码和开发文档了解(让你的移动布局)
在android学习,行动互动是软件的重要组成部分,其中Scroller是提供了拖动效果的类,在网上.比方说一些Launcher实现滑屏都能够通过这个类去实现.. 样例相关博文:Android 仿 窗 ...
- 【android】ImageView的src和background以及两者之间的神奇的差异
一.ImageView中XML属性src和background的差别: background会依据ImageView组件给定的长宽进行拉伸.而src就存放的是原图的大小,不会进行拉伸.src是图片内容 ...
- javascript活动
在javascript倘若有知识的三个方面.事件的第一,流程,其次,事件处理,第三,事件对象.下面就我个人的理解,,分别讲述一下这三个方面的内容. 第一.事件流 事件流指的是事件依照一定的顺序触发.它 ...
- ReactJS.NET
初探ReactJS.NET 开发 ReactJS通常也被称为"React",是一个刚刚在这场游戏中登场的新手.它由Facebook创建,并在2013年首次发布.Facebook认为 ...
- CSharp设计模式读书笔记(15):命令模式(学习难度:★★★☆☆,使用频率:★★★★☆)
命令模式(Command Pattern):将一个请求封装为一个对象,从而让我们可用不同的请求对客户进行参数化:对请求排队或者记录请求日志,以及支持可撤销的操作.命令模式是一种对象行为型模式,其别名为 ...
- 流动python - 八皇后问题简单解决方案
思维: 使用DFS. 坐标的一维阵列的表达,在标行,元素列.A[i]=j它表示第一i女王就行了j柱. 以穿越线,由线(从上到下),决定其列(左到右),所以,不要推断冲突的行,和主斜线副斜线冲突. (行 ...
- Swift # 柯里化函数
前言 此次文章,讲述的是Swift的一个新特性(柯里化函数),可能很多iOS开发人员是第一次听这个词汇,包括我自己也是,自己也用了几天时间才总结出来,希望能帮助到各位咯,个人感觉偏向有开发经验的码友, ...
- GitFlow使用说明
———————安装--------------- $ git clone --recursive git://github.com/nvie/gitflow.git $ cd gitflow $ [s ...