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 ! -你不知道你是如此的美丽动人,这就是你美丽动人的所在!

  如果你觉得本篇文章对你有所帮助,请点击右下部“推荐”,^_^

  参考资料:

Unit Of Work-工作单元的更多相关文章

  1. ABP(现代ASP.NET样板开发框架)系列之12、ABP领域层——工作单元(Unit Of work)

    点这里进入ABP系列文章总目录 基于DDD的现代ASP.NET开发框架--ABP系列之12.ABP领域层——工作单元(Unit Of work) ABP是“ASP.NET Boilerplate Pr ...

  2. ABP领域层——工作单元(Unit Of work)

    ABP领域层——工作单元(Unit Of work) 点这里进入ABP系列文章总目录 基于DDD的现代ASP.NET开发框架--ABP系列之12.ABP领域层——工作单元(Unit Of work) ...

  3. 解析ABP框架中的事务处理和工作单元,ABP事务处理

    通用连接和事务管理方法连接和事务管理是使用数据库的应用程序最重要的概念之一.当你开启一个数据库连接,什么时候开始事务,如何释放连接...诸如此类的. 正如大家都知道的,.Net使用连接池(connec ...

  4. [Abp 源码分析]六、工作单元的实现

    0.简介 在 Abp 框架内部实现了工作单元,在这里讲解一下,什么是工作单元? Unit Of Work(工作单元)模式用来维护一个由已经被业务事物修改(增加.删除或更新)的业务对象组成的列表.Uni ...

  5. [.NET领域驱动设计实战系列]专题四:前期准备之工作单元模式(Unit Of Work)

    一.前言 在前一专题中介绍了规约模式的实现,然后在仓储实现中,经常会涉及工作单元模式的实现.然而,在我的网上书店案例中也将引入工作单元模式,所以本专题将详细介绍下该模式,为后面案例的实现做一个铺垫. ...

  6. 换个角度说工作单元(Unit Of Work):创建、持有与API调用

    看到一些工作单元的介绍,有两种感觉,第一种是很学院,说了等于没说,我估计很多都是没有自己引入到实际的项目中去,第二种是告诉我一种结果,说这就是工作单元,但是没说为什么要这么使用.所以,本篇想要探讨的是 ...

  7. 工作单元(Unit of Work)

    维护受业务事务影响的对象列表,并协调变化的写入和并发问题的解决. 从DB中存取Data时,必须记录增删改动作,以将对DB有影响的数据写会到DB中去. 如果在每次修改对象模型时就对DB进行相应的修改,会 ...

  8. ABP理论学习之工作单元(Unit of Work)

    返回总目录 本篇目录 公共连接和事务管理方法 ABP中的连接和事务管理 仓储类 应用服务 工作单元 工作单元详解 关闭工作单元 非事务的工作单元 工作单元方法调用其它 工作单元作用域 自动保存 IRe ...

  9. 基于DDD的.NET开发框架 - ABP工作单元(Unit of Work)

    返回ABP系列 ABP是“ASP.NET Boilerplate Project (ASP.NET样板项目)”的简称. ASP.NET Boilerplate是一个用最佳实践和流行技术开发现代WEB应 ...

  10. 【.Net设计模式系列】工作单元(Unit Of Work)模式 ( 二 )

    回顾 在上一篇博客[.Net设计模式系列]仓储(Repository)模式 ( 一 ) 中,通过各位兄台的评论中,可以看出在设计上还有很多的问题,在这里特别感谢 @横竖都溢 @ 浮云飞梦 2位兄台对博 ...

随机推荐

  1. Android Bitmap OutOfMemory 解决的方法

    在Android应用里,最耗费内存的就是图片资源.并且在Android系统中.读取位图Bitmap时,分给虚拟机中的图片的堆栈大小仅仅有8M.假设超出了.就会出现OutOfMemory异常 E/And ...

  2. 如何基于对话框的project基于改变BCG的

    一,stdafx.h 增加在下面的例子.BCGCBProInc.h间接介绍lib.   #include <BCGCBProInc.h> // BCGControlBar Pro #if ...

  3. 利用纯CSS3实现超立体的3D图片侧翻倾斜效果

    原文:利用纯CSS3实现超立体的3D图片侧翻倾斜效果 上午的时候我在jQuery论坛上看到网友分享的一款CSS3 3D图片侧翻倾斜特效,觉得效果非常棒,其实话说回来,这玩意儿的实现真的非常简单,主要是 ...

  4. 对于VS相关的插件

    原文:对于VS相关的插件 本人使用这款IDE时间不长,但是很佩服其强大的功能. 编写代码时候的插件辅助,确实让人很舒服. 网上找了好多,有几个是很有用的,但是忘记了他们的网址,再次,总结下,也是给自己 ...

  5. 关于通过id查询记录的一些总结

    最近在做一个oa系统,简化了账号的设置,列名均为id,类型均为varchar:有的表将id设置成了主键,有的表没有设置成主键. 通过举例说明通过id查询的一些问题. 之前登陆的时候,账号001-007 ...

  6. HDU-4862-Jump

    比今年第二个问题,第一个田间学校更多.在游戏中可以做不做,卡在K一旦有.阅读解决一个问题后,才做.内置图所示k这的确是很聪明倍. 代码: #include<cstdio> #include ...

  7. SQL于DML(数据库操作语言)采用

    1.Insert语句: INSERT [INTO] table [(column1, column2, column3, . . .)] VALUES(value1, value2, value3, ...

  8. Linux下Nagios

    Linux下Nagios的安装与配置   一.Nagios简介 Nagios是一款开源的电脑系统和网络监视工具,能有效监控Windows.Linux和Unix的主机状态,交换机路由器等网络设置,打印机 ...

  9. C#面向对象复习概要

    1.面向对象:我们将具有统一行为和属性的对象抽象划分为类,通过类去创建对象.这种编程思想叫做面向对象的编程思想. 2.属性:对象具有的属性 using System; using System.Col ...

  10. ZOJ 2724 Windows 消息队列 (优先队列)

    链接:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=2724 Message queue is the basic fund ...