zoukankan      html  css  js  c++  java
  • Unit Of Work-工作单元

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

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

      参考资料:

  • 相关阅读:
    关于git---远程
    关于git---主要
    css特效
    Canvas图片压缩
    TypeScript简单介绍
    html 常见兼容性问题及解决方法
    cookies,sessionStorage 和 localStorage 的区别
    vue-element-admin vue.config.js
    ② nodejs + mongodb 搭建服务器
    ① 数据自动填充
  • 原文地址:https://www.cnblogs.com/Leo_wl/p/3754031.html
Copyright © 2011-2022 走看看