UnitOfWork实战

企业模式之Unit Of Work模式

  在开始UnitOfWork模式之前有必要回顾下我们耳熟能详的Data Access Object(DAO)模式,即数据访问对象。DAO是一种简单的模式,我们构建应用的时候经常会使用到它,它的功能就是将DAL元素从应用程序中分离出 来,在经典的三层架构中,我们会将数据持久化工作单独分离出来,封装成DAL层。但是,DAO并没有隐藏它面对是一张张数据表,而且通常情况我们会为数据 库中的每一张表创建一个DAO类,想必大家对这种方式的极度的不爽了,。

由于DAO模式与数据表是一对一匹配的关系,因此DAO模式很好的配合了Active Record和Transaction Script业务模式,尤其是Table Module。正因为这种与数据表一对一匹配关系,使我对DAO模式深恶痛绝。

  Unit Of Work模式,即工作单元,它是一种数据访问模式。它是用来维护一个由已经被业务修改(如增加、删除和更新等)的业务对象组成的列表。它负责协调这些业务 对象的持久化工作及并发问题。那它是怎么来维护的一系列业务对象组成的列表持久化工作的呢?通过事务。Unit Of Work模式会记录所 有对象模型修改过的信息,在提交的时候,一次性修改,并把结果同步到数据库。 这个过程通常被封装在事务中。所以在DAL中采用Unit Of Work模式好处就在于能够确保数据的完整性,如果在持有一系列业务对象(同属于一个事务)的过程中出现问题,就可以将所有的修改回滚,以确保数据始终处 于有效状态,不会出现脏数据。

  在这里我们,使用一个简单的银行领域对两个帐号之间的转账进行举例

首先如图进行分层搭建基础框架

  总共分为四层依次是:    ---> 引用关系

  UnitOfWork.Console        --->UnitOfWork.Infrastructure、UnitOfWork.Model、UnitOfWork.Repository

  UnitOfWork.Infrastructure

  UnitOfWork.Model    --->UnitOfWork.Infrastructure

  UnitOfWork.Repository  --->UnitOfWork.Model、UnitOfWork.Infrastructure

  这不是经典的领域驱动架构,因为业务简单就进行简单搭建。

  UnitOfWork.Infrastructure:

  首先,在UnitOfWork.Infrastructure建了一个Domain文件夹,里面只建了一个IAggregateRoot接口,Unit Of Work操作的实体必须是实现IAggregateRoot接口的。

    /// <summary>
    /// 标识接口,定义聚合根
    /// </summary>
    public class IAggregateRoot
    {

    }

  建立UnitOfWork文件夹,在里面添加一个IUnitOfWorkRepository接口

    public interface IUnitOfWorkRepository
    {
        //新增
        void PersistCreationOf(IAggregateRoot entity);
        //更新
        void PersistUpdateOf(IAggregateRoot entity);
        //删除
        void PersistDeletionOf(IAggregateRoot entity);
    }

  我们再向UnitOfWork文件夹中添加一个IUnitOfWork接口,IUnitOfWork接口在注册更新、新增和删除时,需要 IUnitOfWorkRepository,这样再提交Commit,UnitOfWork可以将真正持久化的工作委托给适合的具体实现对象,其实就是 将持久化工作交给了IUnitOfWorkRepository的实现类,我们稍后看看IUnitOfWork的实现类你就清楚了。

  public interface IUnitOfWork
    {
        /// <summary>
        /// 更新
        /// </summary>
        /// <param name="entity"></param>
        /// <param name="unitofWorkRepository"></param>
        void RegisterUpdate(IAggregateRoot entity, IUnitOfWorkRepository unitofWorkRepository);
        /// <summary>
        /// 新增
        /// </summary>
        /// <param name="entity"></param>
        /// <param name="unitofWorkRepository"></param>
        void RegisterAdd(IAggregateRoot entity, IUnitOfWorkRepository unitofWorkRepository);
        /// <summary>
        /// 删除
        /// </summary>
        /// <param name="entity"></param>
        /// <param name="unitofWorkRepository"></param>
        void RegisterRemoved(IAggregateRoot entity, IUnitOfWorkRepository unitofWorkRepository);
        /// <summary>
        /// 提交
        /// </summary>
        void Commit();
    }

  顺便说一句,在UnitOfWork.Infrastructure,我还建立的Common文件夹,Logging文件夹,所要表达的意思是Infrastructure意为基础设施层,我们可以将通用的组件放到这里面,比如日志组件,邮件组件等。

好了,回顾下,我们在UnitOfWork.Infrastructure中其实什么业务都没有处理,只定义了三个接口。

  UnitOfWork.Model

  接下来,说说这层干了什么事吧!这一层主要是处理两个账户之间转账的业务。

  向UnitOfWork.Model中添加一个Account类,实现IAggregateRoot接口,表示它是一个聚合根,可以被Unit Of Work操作。

    /// <summary>
    /// 账户类,表示Account是集合根
    /// </summary>
    public class Account : IAggregateRoot
    {
        public Account(decimal balance)
        {
            Balance = balance;
        }
        /// <summary>
        /// 账户余额
        /// </summary>
        public decimal Balance { get; set; }
    }

  为了持久化Account类,我们添加的一个仅包含了示例有关的的Repository接口,即IAccountRepository,只是简单的示例。

    /// <summary>
    /// 定义持久化操作
    /// </summary>
    public interface IAccountRepository
    {
        /// <summary>
        /// 更新
        /// </summary>
        /// <param name="account"></param>
        void Save(Account account);
        /// <summary>
        /// 新增
        /// </summary>
        /// <param name="account"></param>
        void Add(Account account);
        /// <summary>
        /// 删除
        /// </summary>
        /// <param name="account"></param>
        void Remove(Account account);
    }

  为了完成转账的业务,我们需要创建一个服务类来协调两个账户之间的转账工作,如AccountService类,在 AccountService类中,通过构造函数初始化了IAccountRepository和IUnitOfWork。在完成转账后,它们都调用了账 户Repository进行持久化。最后,通过Unit Of Work的Commit来确保该笔交易的完成。

    public class AccountService
    {
        private IAccountRepository _accountRepository;
        private IUnitOfWork _unitOfWork;

        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();
            }
        }
    }

  总结下,在UnitOfWork.Model中我们定义的一个Account类,定义了一个持久化Account类的接口,以及转账业务的完 成。下面我们要进入UnitOfWork.Repository探究Repository和Unit Of Work之间是怎么交互的?

  UnitOfWork.Repository:

  在UnitOfWork.Repository,添加了一个NHUnitOfWork类,实现了 UnitOfWork.Infrastructure.UnitOfWork中的IUnitOfWork接口,为什么定义到这里。因为在项目开发中你可能 有NHbernator的Repository和EF的Repository。还记得我在讲解IUnitOfWork接口时,曾说过这样一句话 “IUnitOfWork将持久化工作交给了IUnitOfWorkRepository的实现类”,在这里你就会找到答案了。

    public class NHUnitOfWork : IUnitOfWork
    {
        private Dictionary<IAggregateRoot, IUnitOfWorkRepository> addedEntities;
        private Dictionary<IAggregateRoot, IUnitOfWorkRepository> changedEntities;
        private Dictionary<IAggregateRoot, IUnitOfWorkRepository> deletedEntities;

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

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

        public void RegisterAdd(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();
            }
        }

  接下来,再添加一个AccountRepository类,这个类实现了两个接口,IAccountRepository和 IUnitOfWorkRepository接口。IAccountRepository中的方法就是简单得将工作交给了Unit Of Work,传入待持久化的实体及Repository(实现了IUnitOfWorkRepository)引用。最后Unit Of Work 引用Repository的IUnitOfWorkRepository契约来完成真正的持久化工作。

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

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

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

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

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

        public void PersistUpdateOf(IAggregateRoot entity)
        {
            // ADO.net code to update the entity...真正的SQL实现
        }

        public void PersistCreationOf(IAggregateRoot entity)
        {
            // ADO.net code to Add the entity...真正的SQL实现
        }

        public void PersistDeletionOf(IAggregateRoot entity)
        {
            // ADO.net code to delete the entity...真正的SQL实现
        }
    }    

  总结下,UnitOfWork.Repository这里才是真正纠结的地方。首先,Unit Of Work加载实体对象(Accont)和实体对应的Repository对象(AccountRepository);然后通过Unit Of Work的Commit方法,循环转调Repository对象(AccountRepository)的持久化方法,进行实体对象(Accont)的持 久化工作。多调试就明白了。

  UnitOfWork.Console:

  接下来,就是最后的控制台程序了。  

    class Program
    {
        static void Main(string[] args)
        {
            Account a = new Account(1000);
            System.Console.WriteLine("现在张三,存有{0}", a.Balance);
            Account b = new Account(200);
            System.Console.WriteLine("现在李四,存有{0}", b.Balance);
            System.Console.WriteLine("张三准备转500元给李四,转战开始了......");

            //声明要使用的UnitOfWork
            IUnitOfWork nhUnitOfWork = new NHUnitOfWork();

            //声明要使用的Repository
            IAccountRepository accountRepository = new AccountRepository(nhUnitOfWork);

            AccountService service = new AccountService(accountRepository, nhUnitOfWork);

            service.Transfer(a,b,500);
            System.Console.WriteLine("转账结束");
            System.Console.WriteLine("张三当前余额:{0}",a.Balance);
            System.Console.WriteLine("李四当前余额:{0}",b.Balance);

            System.Console.ReadKey();
        }
    }

源码下载

时间: 2024-08-13 23:01:07

UnitOfWork实战的相关文章

【无私分享:ASP.NET CORE 项目实战(第五章)】Repository仓储 UnitofWork

目录索引 [无私分享:ASP.NET CORE 项目实战]目录索引 简介 本章我们来创建仓储类Repository 并且引入 UnitOfWork 我对UnitOfWork的一些理解  UnitOfWork 工作单元,对于这个的解释和实例,网上很多很多大神之作,我在这就不班门弄斧了,只是浅谈 一下个人理解,不一定对,希望大家指正: UnitOfWork 看了很多,个人理解就是 统一事务,在很多操作中我们可能是进行多项操作的,比如 同时保存两个表的数据,如果我们先保存一个表(SaveChanges

Repository仓储 UnitofWork

Repository仓储 UnitofWork 目录索引 [无私分享:ASP.NET CORE 项目实战]目录索引 简介 本章我们来创建仓储类Repository 并且引入 UnitOfWork 我对UnitOfWork的一些理解  UnitOfWork 工作单元,对于这个的解释和实例,网上很多很多大神之作,我在这就不班门弄斧了,只是浅谈 一下个人理解,不一定对,希望大家指正: UnitOfWork 看了很多,个人理解就是 统一事务,在很多操作中我们可能是进行多项操作的,比如 同时保存两个表的数

【机器学习实战】Machine Learning in Action 代码 视频 项目案例

MachineLearning 欢迎任何人参与和完善:一个人可以走的很快,但是一群人却可以走的更远 Machine Learning in Action (机器学习实战) | ApacheCN(apache中文网) 视频每周更新:如果你觉得有价值,请帮忙点 Star[后续组织学习活动:sklearn + tensorflow] ApacheCN - 学习机器学习群[629470233] 第一部分 分类 1.) 机器学习基础 2.) k-近邻算法 3.) 决策树 4.) 基于概率论的分类方法:朴素

下载-深入浅出Netty源码剖析、Netty实战高性能分布式RPC、NIO+Netty5各种RPC架构实战演练三部曲视频教程

下载-深入浅出Netty源码剖析.Netty实战高性能分布式RPC.NIO+Netty5各种RPC架构实战演练三部曲视频教程 第一部分:入浅出Netty源码剖析 第二部分:Netty实战高性能分布式RPC 第三部分:NIO+Netty5各种RPC架构实战演练

C#网络编程技术FastSocket实战项目演练

一.FastSocket课程介绍 .NET框架虽然微软提供了socket通信的类库,但是还有很多事情要自己处理,比如TCP协议需要处理分包.组包.粘包.维护连接列表等,UDP协议需要处理丢包.乱序,而且对于多连接并发,还要自己处理多线程等等.本期分享课程阿笨给大家带来的是来源于github开源Socket通信中间件:FastSocket,目的就是把大家从繁琐的网络编程技术中彻底地解放和释放出来. 阿笨只想安安静静的学习下网络编程技术Socket后,将学习的成果直接灵活的运用到自己的实际项目中去.

下载Java8实战视频教程

1.15套java架构师,高并发,分布式,集群,大型分布式综合项目实战详情:https://my.oschina.net/java168/blog/863547 2.36套精品Java高级课及架构课,亿级流量,P2P金融,第三方支付,设计模式实战,程序调优,系统设计:https://my.oschina.net/java168/blog/1539323 下载Java8实战视频教程

[js高手之路]设计模式系列课程-组合模式+寄生组合继承实战新闻列表

所谓组合模式,就是把一堆结构分解出来,组成在一起,现实中很多这样的例子,如: 1.肯德基套餐就是一种组合模式, 比如鸡腿堡套餐,一般是是由一个鸡腿堡,一包薯条,一杯可乐等组成的 2.组装的台式机同理,由主板,电源,内存条,显卡, 机箱,显示器,外设等组成的 把一个成型的产品组成部件,分成一个个独立的部件,这种方式可以做出很多灵活的产品,这就是组合模式的优势 比如:家用台式机电脑,要求配置比较低, 这个时候只需要主板+电源+内存条+机箱+显示器+外设就可以了,不需要配置独立显卡 鸡腿堡+鸡翅+紫薯

秒杀系统架构分析与实战

0 系列目录 秒杀系统架构 秒杀系统架构分析与实战 1 秒杀业务分析 正常电子商务流程 (1)查询商品:(2)创建订单:(3)扣减库存:(4)更新订单:(5)付款:(6)卖家发货 秒杀业务的特性 (1)低廉价格:(2)大幅推广:(3)瞬时售空:(4)一般是定时上架:(5)时间短.瞬时并发量高: 2 秒杀技术挑战 假设某网站秒杀活动只推出一件商品,预计会吸引1万人参加活动,也就说最大并发请求数是10000,秒杀系统需要面对的技术挑战有: 对现有网站业务造成冲击 秒杀活动只是网站营销的一个附加活动,

Lambda表达式实战视频教程

视频教程地址: https://my.oschina.net/u/3217554/blog/1507456 1:Lambda表达式及函数式接口介绍 2:Lambda表达式详解 3:方法的引用(一) 4:方法的引用(二) 5:Stream API(一) 6:Stream API(二) 7:Lambda表达式.方法的引用.Stream API实战