文档章节

Thinking In Design Pattern——Unit Of Work(工作单元)模式探索

 木宛城主
发布于 2015/03/02 19:38
字数 1303
阅读 31
收藏 0
点赞 0
评论 0

什么是Unit Of Work模式

Unit Of Work(工作单元)模式用来维护一个由已经被业务事物修改(增加、删除或更新)的业务对象组成的列表。Unit  Of Work模式负责协调这些修改的持久化工作以及所有标记的并发问题。在数据访问层中采用Unit Of Work模式带来的好处是能够确保数据完整性。如果在持久化一系列业务对象(他们属于同一个事物)的过程中出现问题,那么应该将所有的修改回滚,以确保数据始终处于有效状态。

为了演示Unit Of Work模式,使用一个简单的银行领域对两个账号之间的转账建模。下图给出了服务层(AccountService)与使用了Unit Of Work模式(以确保转账作为原子事物的Unit Of Work提交)的资源层(AccountRepository)之间的交互。

 

记住这张图,因为下面的代码逻辑都是依照这张图的定义来实现的。

建立Infrastructure

  • 下面开始编写解决方案的代码,首先创建Unit Of Work模式的所有配套的基础设施代码
public interface IAggregateRoot
    {
    }

IAggregateRoot接口实际上属于标记接口,这个接口充当了类和方法的元数据,我们构建的资源库只持久化实现了IAggregateRoot接口的业务对象,所以Unit Of Work的实现将使用IAggregateRoot接口来引用原子事物中涉及的任何业务实体

  • 添加另外一个接口IUnitOfWorkRepository,这是一个用来持久化操作的接口:
public interface IUnitOfWorkRepository
    {
        void PersistCreationOf(IAggregateRoot entity);
        void PersistUpdateOf(IAggregateRoot entity);
        void PersistDeletionOf(IAggregateRoot entity);
    }
  • 之后,向Infrastructure项目中添加IUnitOfWork接口:
public interface IUnitOfWork
    {
        void RegisterAmended(IAggregateRoot entity, IUnitOfWorkRepository unitofWorkRepository);
        void RegisterNew(IAggregateRoot entity, IUnitOfWorkRepository unitofWorkRepository);
        void RegisterRemoved(IAggregateRoot entity, IUnitOfWorkRepository unitofWorkRepository);
        void Commit();
    }

 值得注意的是IUnitOfWork接口在注册修改/增加/删除时需要IUnitOfWorkRepository,这样在提交时,Unit Of Work可以将真正持久化的工作委托给适当的具体实现。

  • 最后向Infrastructure项目中添加UnitOfWork,实现IUnitOfWork:
public class UnitOfWork : IUnitOfWork 
    {
        private Dictionary<IAggregateRoot, IUnitOfWorkRepository> addedEntities;
        private Dictionary<IAggregateRoot, IUnitOfWorkRepository> changedEntities;
        private Dictionary<IAggregateRoot, IUnitOfWorkRepository> deletedEntities;

        public UnitOfWork()
        {
            addedEntities = new Dictionary<IAggregateRoot, IUnitOfWorkRepository>();
            changedEntities = new Dictionary<IAggregateRoot, IUnitOfWorkRepository>();
            deletedEntities = new Dictionary<IAggregateRoot, IUnitOfWorkRepository>();
        }

        public void RegisterAmended(IAggregateRoot entity, IUnitOfWorkRepository unitofWorkRepository)
        {
            if (!changedEntities.ContainsKey(entity))
            {
                changedEntities.Add(entity, unitofWorkRepository);
            }
        }

        public void RegisterNew(IAggregateRoot entity, IUnitOfWorkRepository unitofWorkRepository)
        {
            if (!addedEntities.ContainsKey(entity))
            {
                addedEntities.Add(entity, unitofWorkRepository);
            };
        }

        public void RegisterRemoved(IAggregateRoot entity, IUnitOfWorkRepository unitofWorkRepository)
        {
            if (!deletedEntities.ContainsKey(entity))
            {
                deletedEntities.Add(entity, unitofWorkRepository);
            }
        }
        
        public void Commit()
        {
            using (TransactionScope scope = new TransactionScope())
            {
                foreach (IAggregateRoot entity in this.addedEntities.Keys)
                {
                    this.addedEntities[entity].PersistCreationOf(entity);
                }

                foreach (IAggregateRoot entity in this.changedEntities.Keys)
                {
                    this.changedEntities[entity].PersistUpdateOf(entity);
                }

                foreach (IAggregateRoot entity in this.deletedEntities.Keys)
                {
                    this.deletedEntities[entity].PersistDeletionOf(entity);
                }

                scope.Complete(); 
            }
        }

    }

UnitOfWork类使用3个字典变量来跟踪对业务实体的代执行修改。第一个字典对应于被添加到数据存储的实体,第2个字典跟踪带更新的实体,而第三个字典处理实体删除,与字典中的实体键匹配的IUnitOfWorkRepository将被保存下来,并用于Commit方法之中,来调用Repository对象,该对象包含真正持久化实体的代码。Commit方法遍历每一个字典,并调用相应的IUnitOfWorkRepository方法(传递实体引用)。Commit方法中的工作均被TransactionScope代码包装起来,如果在IUnitOfWorkRepository中执行任务时出现异常,则所有工作回滚,数据存储将保持原来的状态。

建立Model

  • 向Model中添加一个新类Account,表示银行账户,为了方便演示简单处理了:
public class Account : IAggregateRoot 
    {
        public decimal balance { get; set; }
    }
  •   为了将Accout持久化,添加IAccountRepository接口:
public interface IAccountRepository
    {
        void Save(Account account);
        void Add(Account account);
        void Remove(Account account);                
    }
  • 添加AccountService服务类来协调两个账户之间的转账工作。
public class AccountService
    {
        private IAccountRepository _accountRepository;
        private IUnitOfWork _unitOfWork;
        /// <summary>
        /// AccountService通过其构造器实现依赖注入
        /// </summary>
        /// <param name="accountRepository"></param>
        /// <param name="unitOfWork"></param>
        public AccountService(IAccountRepository accountRepository,
                              IUnitOfWork unitOfWork)
        {
            _accountRepository = accountRepository;
            _unitOfWork = unitOfWork;            
        }
        /// <summary>
        /// 实现两个账户之间转账工作
        /// </summary>
        /// <param name="from"></param>
        /// <param name="to"></param>
        /// <param name="amount"></param>
        public void Transfer(Account from, Account to, decimal amount)
        {
            if (from.balance >= amount)
            {
                from.balance -= amount;
                to.balance += amount;

                _accountRepository.Save(from);
                _accountRepository.Save(to);
                _unitOfWork.Commit();
            }
        }
    }

接着,它调用账户Repository来保存两个账户,最后,它调用Unit Of Work实例的Commit方法来确保该交易作为原子的Unit Of Work完成。所以接下来的重点就是怎样Repository与Unit Of Work交互。

建立Repository来持久化业务实体

public class AccountRepository : IAccountRepository, IUnitOfWorkRepository 
    {
        private IUnitOfWork _unitOfWork;

        public AccountRepository(IUnitOfWork unitOfWork)
        {
            _unitOfWork = unitOfWork;
        }

        public void Save(Account account)
        {            
            _unitOfWork.RegisterAmended(account, this);            
        }

        public void Add(Account account)
        {
            _unitOfWork.RegisterNew(account, this);
        }

        public void Remove(Account account)
        {
            _unitOfWork.RegisterRemoved(account, this);
        }  

        public void PersistUpdateOf(IAggregateRoot entity)
        {
            // ADO.net or EF、NH来持久化
        }

        public void PersistCreationOf(IAggregateRoot entity)
        {
            // ADO.net or EF、NH来持久化
        }

        public void PersistDeletionOf(IAggregateRoot entity)
        {
            // ADO.net or EF、NH来持久化
        }              
    }

OK,这样Unit Of Work工作模式就搭建好了,AccountRepository实现了IAccountRepositoryIUnitOfWorkRepository接口,IAccountRepository方法的实现简单地将工作委托给Unit Of Work(传入待持久化的实体以及Repository的引用),最后,调用Unit Of Work类的Commit方法,其实是Unit Of Work引用Repository的IUnitOfWorkRepository的接口契约来真正完成持久化任务,至于持久化操作你可以用Ado.net或者EF、NH等。

回过头来再看这幅图,原来Unit Of Work也就是如此罢了:

© 著作权归作者所有

共有 人打赏支持
粉丝 2
博文 222
码字总数 199010
作品 0
黄浦
软件人员推荐书目

软件人员推荐书目(一) 大师篇 一、 科学哲学和管理哲学 【1】 "程序开发心理学"(The Psychology of Computer Programming : Silver Anniversary Edition) 【2】 "系统化思维导论"(An Introd...

LsDimplex
2016/12/06
14
0
AOP 快速开发框架--IronFramework

IronFramework 基于 领域驱动设计 Domain Driven Design (DDD), 多层构架,Aspect-oriented programming(AOP) 快速开发框架 基于 Microsoft .Net Framework 企业级解决方案: 特点Features: N...

Megadotnet
2015/10/01
1K
0
Let’s discuss MVVM for iOS

Some say that as you progress as a software developer you undergo specific stages - First, you’re glad you’ve made contribution to the code. You go around telling people that......

hejunbinlan
2016/01/13
13
0
hibernate对象的三种状态

hibernate提供了三种对象状态 瞬时(Transient) — 由 new 操作符创建,且尚未与Hibernate Session 关联的对象被认定为瞬时(Transient)的。瞬时(Transient)对象不会被持久化到数 据库中...

rainumdo
2017/09/04
0
0
10 条“有争议”的编程观点

在Stack Overflow上有这样的一个贴子《What’s your most controversial programming opinion?》,翻译成中文就是“你认为最有争议的编程观点是什么?”,不过,在400多个主回贴,以及上千个...

oschina
2012/05/14
4.2K
10
设计模式Java版,Gitbook开源电子书,含源码

Sunny在CSDN技术博客中陆续发表了100多篇与设计模式学习相关的文章,涵盖了七个面向对象设计原则和24个设计模式(23个GoF设计模式 + 简单工厂模式),为了方便大家学习,http://quanke.name ...

quanke_
2016/05/03
1K
5
Why use an interface?

From time to time I run into developers who ask the question, “what is the point of using an interface?” This is usually followed by a statement such as… “I just new up a c......

Jeff Ronay
2017/12/27
0
0
开源图书--设计模式Java版

Sunny在CSDN技术博客中陆续发表了100多篇与设计模式学习相关的文章,涵盖了七个面向对象设计原则和24个设计模式(23个GoF设计模式 + 简单工厂模式),为了方便大家学习,quanke 现将所有文章...

匿名
2016/05/09
1K
0
python 与设计模式 ——工厂与装饰者

python 与设计模式第二篇 添加了test.py,里面的单元测试有使用的方法。 源码地址:[http://git.oschina.net/duoduo3_69/python_design_pattern][1] git checkout v002(这个版本与此篇博客相符...

duoduo3_69
2013/11/27
0
1
从状态模式看 JavaScript 与 Java

写作时间 2016-10-29 这篇文章缘起于前几天微博上有关动态语言与静态语言的讨论,因为有几个编程高手参加,所以能看到一些特别有启发性的发言。本文主要是下面这一条微博的读后感,也是我的练...

天方夜
07/04
0
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

切分log日志

新建logback.xml放到resource里面 <?xml version="1.0" encoding="utf-8"?><configuration> <appender name="consoleLog" class="ch.qos.logback.core.ConsoleAppender"> <......

talen
1分钟前
0
0
spring @Resource 和 @Autowired 的使用区别

这两个 注解 @Resource 和 @Autowired , 常识都知道 @Resource 是 JAVAEE 自带的,@Autowired 是 spring 的自定义注解。 一般情况下, 使用 bean的时候, 这两个注解 随便使用一个即可。 但...

之渊
6分钟前
0
0
崛起于Springboot2.X之集成MongoDB使用Repository增删改查(26)

1、pom依赖 <dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> <version>1.2.7</version></dependency><dependency> <groupId>log4j</......

木九天
8分钟前
0
0
springboot集成elasticsearch客户端问题记录

1背景说明 服务端ES版本为5.5.2,springboot版本为1.5.6。 工程中添加如下依赖 2问题记录 2.1 NetworkPlugin类找不到 报错java.lang.ClassNotFoundException: org.elasticsearch.plugins.Net...

zjg23
8分钟前
0
0
快速构建ceph可视化监控系统

前言 ceph的可视化方案很多,本篇介绍的是比较简单的一种方式,并且对包都进行了二次封装,所以能够在极短的时间内构建出一个可视化的监控系统 本系统组件如下: ceph-jewel版本 ceph_expor...

万建宁
8分钟前
0
0
Java构造器使用注意

public class 父类A {int age = 10;protected void say() {System.out.println("父类A");}public 父类A() {override();}public void override() {Syst...

咸鱼AI
8分钟前
0
0
TensorFlow 线性分类

构造直线 z = 2 * x - 3 * y + 4 x0*w0+x1*w1+b=0 x1=-x0* w0/w1-b/w1 斜率 k= -w0/w1 截距 -b/w1 随机生成数据,加入一定的偏差,用直线将二维平面分为两部分 使用线性模型拟合参数 损失函数...

阿豪boy
11分钟前
0
0
翻译冒泡排序测试

翻译一个冒泡排序: var a = [1,3,2,4,6,5];var f = 0;var n = a.length ;for( var i =1; i<= n; i++) { for( var j = n-1 ; j >= i; j --) { if(a[j] < a[j+1]) { ......

钟元OSS
13分钟前
0
0
maven父、子级版本号同时修改

命令: mvn versions:set -DnewVersion=0.0.2-SNAPSHOT

沉默的懒猫
14分钟前
0
0
Spring boot中的异常处理之注解响应

Controller层 return patientRepository.findById(id) .orElseThrow(() -> new NotFoundException(String.format("Patient %d not found", id))); Exception类 @ResponseS......

亚林瓜子
15分钟前
0
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部