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控制控制的显示顺序

    在android中假设首先在xml中静态加入了一个控件,剩下的控件都是通过addView动态加入.那么假设有控件覆盖的情况(比方说使用FrameLayout或者RelativeLayout),先加入得 ...

  2. deepinmind(转)

    http://it.deepinmind.com/ 花名有孚,支付宝工程师 有希望加入支付宝的同学,可以把简历发到我的个人邮箱spidercoco@gmail.com

  3. 一张地图告诉你,只JavaScript不够!

    这将是JavaScript语法,你真的会一JavaScript嘛.看看这个图片!超好用JavaScript一本书的摘录游.熊儿.快去学习! 版权声明:本文博客原创文章.博客,未经同意,不得转载.

  4. ORACLE在表中添加的目光凝视和读取列

    在ORACLE中给表.列添加凝视以及读取凝视 1.给表填加凝视:SQL>comment on table 表名 is '表凝视"; 2.给列加凝视:SQL>comment on ...

  5. Swift使用单个案件管理FMDB数据库

    下班... 抢 我曾经Swift使用单一个案管理FMDB数据库的方法共享出来: // Created by 秦志伟 on 14-6-12. import UIKit class ZWDBManager ...

  6. 第4章 建造者模式(Builder Pattern)

    原文 第4章 建造者模式(Builder Pattern) 定义 将一个复杂对象的构造与它的表示分离,使同样的构建过程可以创建不同的表示,这样的设计模式被称为建造者模式. 实用范围 1 当创建复杂对象 ...

  7. 关于system()的一些用法

    C语库函数 函数名: system  功  能: 发出一个DOS命令  用  法: int system(char *command);  它包含头文件<stdlib.h>  system ...

  8. SQL字符串转换为数组

    /*一.按指定符号分割字符串,返回分割后的元素个数,方法很简单,就是看字符串中存在多少个分隔符号,然后再加一,就是要求的结果. -----rtrim(@str)去掉 @str右边的字符 ltrim(@ ...

  9. Eclipse部署Web项目(图文讲解)

    讲解是在linux下完成的,但对windows系统,操作也是一样的,不要被吓到了 1.下载Eclipse

  10. 【转】UiAutomator简要介绍

    原文地址:http://blog.csdn.net/g19920917/article/details/16131565 3.1.必备条件: 1.JDK    2.SDK(API高于15)    3. ...