在DDD开发过程中,一个良好的Uow设计必不可少,我心目中的Uow设计应该具备以下几点:

1、有着良好的抽象,有着恰如其分的命名;

2、能够应付不同的组件,比如你的系统中可能会存在EfUnitOfWork、RedisUnitOfWork;

3、易于使用,不用开发者显示调用。Uow在一个用户请求开始到结束能够自动包裹在业务逻辑外边;

在阅读了Abp的源码后我感觉Abp中的Uow正好符合我这几点要求,但是其实现稍有点复杂,例如在EfUnitOfWork中加入了DynamicFilters,EfUnitOfWork支持多DbContext,这些复杂性导致EfUnitOfWork类变得有点臃肿。所以我在实例代码中移除了这些设计。

一、业务抽象

一个使用Uow的典型代码片段如下:

            using (var uow = UowManager.Begin())
{
//....logic uow.Commit();
}

从这段代码中我们基本可以分析出下面的Uow抽象。

1、IUnitOfWorkManager

从上面的代码片段可以看出,此Manager应该具有一个Begin()方法,返回IDisposable类型。

2、IUnitOfWorkCompleteHandle

IUnitOfWorkManager的Begin()方法返回的IDisposable类型应该具有Commit()的能力,该抽象用于对IUnitOfWork的提交和释放资源。

3、IUnitOfWork

从这个代码片段中我们并没有看到IUnitOfWork这个抽象,原因在于IUnitOfWorkManager隐藏了具体的IUnitOfWork,IUnitOfWorkManager.Begin()实现中实际上是具体的IUnitOfWork.Begin()调用。

4、ICurrentUnitOfWorkProvider

针对用户在一次上下文中的请求,具有唯一的一个IUnitOfWork,因此可以在任意时刻通过ICurrentUnitOfWorkProvider来读取当前上下文的IUnitOfWork。

通过接口命名描述就能理清整个Uow设计思路:

二、EfUnitOfWork

EfUnitOfWork的Begin体现在对TransactionScope的调用、Commit体现在对dbContext.SaveChanges()的调用

        public void Begin(UnitOfWorkOptions options)
{
_transactionScope = new TransactionScope(
options.TransactionScopeOption.GetValueOrDefault(_defaultUnitOfWorkOptions.TransactionScopeOption),
new TransactionOptions()
{
IsolationLevel = options.IsolationLevel.GetValueOrDefault(_defaultUnitOfWorkOptions.IsolationLevel),
Timeout = options.Timeout.GetValueOrDefault(_defaultUnitOfWorkOptions.Timeout)
});
}
        public void Complete()
{
try
{
_dbContext.SaveChanges();
_transactionScope?.Complete(); _completed?.Invoke();
}
catch
{
_failed?.Invoke();
throw;
} }

三、通过Castle实现Aop,将Uow包裹ApplicationService层

定义UnitOfWorkInterceptor,该拦截器表现为要对现有的一个方法包裹UnitOfWork实现。

        private void PerformUow(IInvocation invocation, UnitOfWorkOptions options)
{
using (var uow = _unitOfWorkManager.Begin(options))
{
invocation.Proceed();
uow.Complete();
}
}

四、缺陷

该方案是一个很优秀的UnitOfWork设计,不过当我们在使用DDD模型时如果引申出了领域事件,该方案则不够理想。当领域模型未能够正确持久化时则不应该发布领域事件。针对这一要求我有两个想法:

1、将发布领域事件注册在UnitOfWorkManager的Completed阶段,确保EfUnitOfWork正确执行后再发布领域事件;

2、抽象出EfUnitOfWorkParticipant、IServiceBusParticipant。在Commit阶段分别Commit这两个participant,有一个失败则Rollback所有的participant。

具体实现请参考:https://git.oschina.net/richieyangs/BookLibrary.git

Unit Of Work的设计的更多相关文章

  1. FocusBI: 使用Python爬虫为BI准备数据源(原创)

    关注微信公众号:FocusBI 查看更多文章:加QQ群:808774277 获取学习资料和一起探讨问题. <商业智能教程>pdf下载地址 链接:https://pan.baidu.com/ ...

  2. DynamIQ扫盲文

    综述: ARM CPU的架构都基于big.LITTLE大小核技术.而再big.LITTLE的基础上,又添加了DynamIQ.单一Cluster中可以又8个core,且支持不同架构的core,以及支持不 ...

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

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

  4. 基于Netty打造RPC服务器设计经验谈

    自从在园子里,发表了两篇如何基于Netty构建RPC服务器的文章:谈谈如何使用Netty开发实现高性能的RPC服务器.Netty实现高性能RPC服务器优化篇之消息序列化 之后,收到了很多同行.园友们热 ...

  5. 初探领域驱动设计(2)Repository在DDD中的应用

    概述 上一篇我们算是粗略的介绍了一下DDD,我们提到了实体.值类型和领域服务,也稍微讲到了DDD中的分层结构.但这只能算是一个很简单的介绍,并且我们在上篇的末尾还留下了一些问题,其中大家讨论比较多的, ...

  6. 关于领域驱动设计(DDD)中聚合设计的一些思考

    关于DDD的理论知识总结,可参考这篇文章. DDD社区官网上一篇关于聚合设计的几个原则的简单讨论: 文章地址:http://dddcommunity.org/library/vernon_2011/, ...

  7. [.NET领域驱动设计实战系列]专题二:结合领域驱动设计的面向服务架构来搭建网上书店

    一.前言 在前面专题一中,我已经介绍了我写这系列文章的初衷了.由于dax.net中的DDD框架和Byteart Retail案例并没有对其形成过程做一步步分析,而是把整个DDD的实现案例展现给我们,这 ...

  8. 电商系统中的商品模型的分析与设计—续

    前言     在<电商系统中的商品模型的分析与设计>中,对电商系统商品模型有一个粗浅的描述,后来有博友对货品和商品的区别以及属性有一些疑问.我也对此做一些研究,再次简单的对商品模型做一个介 ...

  9. 我的“第一次”,就这样没了:DDD(领域驱动设计)理论结合实践

    写在前面 插一句:本人超爱落网-<平凡的世界>这一期,分享给大家. 阅读目录: 关于DDD 前期分析 框架搭建 代码实现 开源-发布 后记 第一次听你,清风吹送,田野短笛:第一次看你,半弯 ...

随机推荐

  1. mac osx 安装redis扩展

    1 php -v查看php版本 2 brew search php|grep redis 搜索对应的redis   ps:如果没有brew 就根据http://brew.sh安装 3 brew ins ...

  2. CSS Position 定位属性

    本篇文章主要介绍元素的Position属性,此属性可以设置元素在页面的定位方式. 目录 1. 介绍 position:介绍position的值以及辅助属性. 2. position 定位方式:介绍po ...

  3. 实例操作JSONP原理

    絮语:按这个步骤走,你就会明白JSONP是什么鬼. 1.工程目录: ng-mywork demo.html test.js 2.nginx的server配置 server { listen ; ser ...

  4. ASP.NET MVC5+EF6+EasyUI 后台管理系统(69)-微信公众平台开发-功能概述

    系列目录 为什么要先发这个文章? 因为接下来的文章是关于微信开发的系列,心中一定要有一个概念,知道自己接下来要做什么功能. 而且微信到处都是坑,我首先要把微信与本地跑通起来才敢发布,否则中间出现坑导致 ...

  5. C++的内存泄漏检测

    C++大量的手动分配.回收内存是存在风险的,也许一个函数中一小块内存泄漏被重复放大之后,最后掏空内存. 这里介绍一种在debug模式下测试内存泄漏的方法. 首先在文件的开头以确定的顺序写下这段代码: ...

  6. win8.1硬盘安装ubuntu14.04双系统

    在网上找了很多方法都失败了,原因是大多数方法都是用mbr方式安装的,如grub4dos,easybcd.以至于连自己都怀疑win8能不能用硬盘安装,差点就去买个u盘来安装了,就在打算放弃的时候在ubu ...

  7. Adaboost提升算法从原理到实践

    1.基本思想: 综合某些专家的判断,往往要比一个专家单独的判断要好.在"强可学习"和"弱科学习"的概念上来说就是我们通过对多个弱可学习的算法进行"组合 ...

  8. JavaWeb——Listener

    一.基本概念 JavaWeb里面的listener是通过观察者设计模式进行实现的.对于观察者模式,这里不做过多介绍,大概讲一下什么意思. 观察者模式又叫发布订阅模式或者监听器模式.在该模式中有两个角色 ...

  9. 深入理解 JavaScript,以及 Linux 下的开发调试工具

    前言 JavaScript 是我接触到的第二门编程语言,第一门是 C 语言.然后才是 C++.Java 还有其它一些什么.所以我对 JavaScript 是非常有感情的,毕竟使用它有十多年了.早就想写 ...

  10. 升级npm

    查看npm的所有版本 运行命令: npm view npm versions 命令运行后,会输出到目前为止npm的所有版本. [ '1.1.25', '1.1.70', '1.1.71', '1.2. ...