首先,重构的想法来源于以下文章:Correct use of Repository and Unit Of Work patterns in ASP.NET MVC,因为我发现在我的框架中,对UnitOfWork使用了错误的设计方法,同时感谢一下文章:Generically Implementing the Unit of Work & Repository Pattern with Entity Framework in MVC & Simplifying Entity Graphs,我的重构设计参考了它。

下面来说说我的具体重构方式。

在原来的代码中,我的Repository<T>泛型继承自IRepository<T>并且在增删改查代码中做了如下处理:

   1:    public virtual void Insert(T entity)
   2:          {
   3:              try
   4:              {
   5:                  if (entity == null)
   6:                      throw new ArgumentException("实体类为空");
   7:                  DbSet.Add(entity);
   8:                  context.SaveChanges();
   9:              }
  10:              catch (DbEntityValidationException dbex)
  11:              {
  12:                  var msg = string.Empty;
  13:                  foreach(var validationErrors in dbex.EntityValidationErrors)
  14:                      foreach(var validateionError in validationErrors.ValidationErrors)
  15:                          msg+=string.Format("Property:{0} Error:{1}",validateionError.PropertyName,validateionError.ErrorMessage);
  16:   
  17:                  var fail = new Exception(msg,dbex);
  18:                  throw fail;
  19:              }
  20:          }

最关键的地方是,我添加了“Context.SaveChanges”方法,这就直接导致UnitOfWork的规则失效。UnitOfWork出现的本身是为了提供事务提交支持。这样直接在Repository中提交,直接导致UnitOfWork功能废弃。

还有个地方就是在前台,通过Autofac注册完毕后,我是这么用的:

   1:   public BookService(IUnitOfWork unitOfWork
   2:              , IBook bookRepository
   3:              , IBookType bookTypeRepository
   4:              , IBookPlace bookPlaceRepository
   5:              , ICacheManager cacheManager
   6:              , ILoggerService logger
   7:              )
   8:          {
   9:              this.unitOfWork = unitOfWork;
  10:              this.bookRepository = bookRepository;
  11:              this.bookTypeRepository = bookTypeRepository;
  12:              this.bookPlaceRepository = bookPlaceRepository;
  13:              this.cacheManager = cacheManager;
  14:              this.logger = logger;
  15:          }
  16:   
  17:          private readonly IUnitOfWork unitOfWork;
  18:          private readonly IBook bookRepository;
  19:          private readonly IBookType bookTypeRepository;
  20:          private readonly IBookPlace bookPlaceRepository;
  21:          private readonly ICacheManager cacheManager;
  22:          private readonly ILoggerService logger;

这样做的话,当以后我们有表删除或者新增的时候,我们不得不维护这样的列表。这完全不符合OO设计原则。

但是如果引入UnitOfWork的话,内部利用Hashtable等实现对Respository的指向,那么在界面我们只要这样写就可以了:

   1:   public BookService(
   2:                IUnitOfWork unitOfWork
   3:              , ICacheManager cacheManager
   4:              , ILoggerService logger
   5:              )
   6:          {
   7:              this.unitOfWork = unitOfWork;
   8:              this.cacheManager = cacheManager;
   9:              this.logger = logger;
  10:          }
  11:   
  12:          private readonly IUnitOfWork unitOfWork;
  13:          private readonly ICacheManager cacheManager;
  14:          private readonly ILoggerService logger;

使用的时候,直接这样实例化就行了:

   1:  var bookPlaceRepository = unitOfWork.Repository<BookPlace>();

这样做完全不用顾虑有新表的添加删除了。代码根本就不用动。

所以,综上两点,UnitOfWork的引入为了解决以下问题:

1.提供全局事务支持。

2.提供对Repository模型的指向。以便于松耦合绑定。

下面是代码重构部分:

IUnitOfWork接口部分:

   1:  using System;
   2:  using TinyFrame.Data.DataRepository;
   3:  using TinyFrame.Data.DomainModel;
   4:   
   5:  namespace TinyFrame.Unitofwork
   6:  {
   7:      public interface IUnitOfWork
   8:      {
   9:          void Commit();
  10:          IRepository<T> Repository<T>() where T : class;
  11:   
  12:          void Dispose(bool disposing);
  13:          void Dispose();
  14:      }
  15:  }

实现部分比较简单,利用Hashtable来保存对Repository的指向:

   1:  using System;
   2:  using System.Data.Entity;
   3:  using TinyFrame.Data.DataRepository;
   4:  using TinyFrame.Data.DomainModel;
   5:  using TinyFrame.Data.DataContext;
   6:  using System.Collections;
   7:   
   8:  namespace TinyFrame.Unitofwork
   9:  {
  10:      public class UnitOfWork : IUnitOfWork
  11:      {
  12:          public UnitOfWork(IDbContext dbContext)
  13:          {
  14:              this.dbContext = dbContext;
  15:          }
  16:   
  17:          private readonly IDbContext dbContext;
  18:          private bool disposed;
  19:          private Hashtable repositorys;
  20:   
  21:          public void Commit()
  22:          {
  23:              dbContext.SaveChanges();
  24:          }
  25:   
  26:          public IRepository<T> Repository<T>() where T:class
  27:          {
  28:              if (repositorys == null)
  29:                  repositorys = new Hashtable();
  30:   
  31:              var type = typeof(T).Name;
  32:   
  33:              if (!repositorys.ContainsKey(type))
  34:              {
  35:                  var repositoryType = typeof(Repository<>);
  36:                  var repositoryInstance = Activator.CreateInstance(repositoryType.MakeGenericType(typeof(T)), dbContext);
  37:                  repositorys.Add(type, repositoryInstance);
  38:              }
  39:              return (IRepository<T>)repositorys[type];
  40:          }
  41:   
  42:          #region Dispose method
  43:          public virtual void Dispose(bool disposing)
  44:          {
  45:              if (!disposed)
  46:                  if (disposing) 
  47:                      dbContext.Dispose();
  48:              disposed = true;
  49:          }
  50:          
  51:          public void Dispose()
  52:          {
  53:              Dispose(true);
  54:              GC.SuppressFinalize(this);
  55:          }
  56:          #endregion
  57:      }
  58:  }

第17行,保持对DbContext的引用,以便于进行提交操作。

第26行,Repository<T>泛型方法,以便于动态返回仓储模型。

需要注意的是,在Repository<T>的实现中,不要再增删改查里面再添加 DbContext.SaveChanges方法,首先是没意义,其次是完全不符合Repository和UnitOfWork的做法。

最后附图一张,表明我对Repository和UnitOfWork的理解:

本章源码下载:

点击这里下载

备份下载地址

TinyFrame升级之七:重构Repository和Unit Of Work的更多相关文章

  1. MVC3+EF4.1学习系列(八)-----利用Repository and Unit of Work重构项目

    项目最基础的东西已经结束了,但是现在我们的项目还不健全  不利于测试 重复性代码多   层与层之间耦合性高  不利于扩展等问题.今天的这章 主要就是解决这些问题的.再解决这些问题时,自己也产生了很多疑 ...

  2. 在Entity Framework 4.0中使用 Repository 和 Unit of Work 模式

    [原文地址]Using Repository and Unit of Work patterns with Entity Framework 4.0 [原文发表日期] 16 June 09 04:08 ...

  3. 转载Repository 和Unit of work的使用说明

    利用Repository and Unit of Work重构项目 文章索引和简介 项目最基础的东西已经结束了,但是现在我们的项目还不健全  不利于测试 重复性代码多   层与层之间耦合性高  不利于 ...

  4. TinyFrame升级之一:框架概览

    由于之前的TinyFrame多于简单,并且只是说明原理,并无成型的框架出来,所以这次我把之前的知识进行了汇总,然后做出了这一版的TinyFrame框架. 整个框架的结构如下: TinyFrame.Da ...

  5. Using the Repository and Unit Of Work Pattern in .net core

    A typical software application will invariably need to access some kind of data store in order to ca ...

  6. TinyFrame升级之三:逻辑访问部分

    在上一篇,我们打造了自己的数据访问部分,这篇,我们准备讲解如何打造逻辑访问部分. 在上一篇中,我们利用Repository模式构建了基于泛型的操作合集.由于这些操作的合集都是原子性的操作,也就是针对单 ...

  7. TinyFrame升级之四:IOC容器

    在这个框架中,我们使用Autofac作为IOC容器,来实现控制反转,依赖注入的目的. 在程序加载的时候,我需要将系统中所有用到的接口与之对应的实现进行装载.由于用户交互部分是在TinyFrame.We ...

  8. TinyFrame升级之九:实现复杂的查询

    本章我们主要讲解如何实现一个复杂的查询.由于目前TinyFrame框架已经投入到了实际的项目生产中,所以我很乐意将项目中遇到的任何问题做以记录并备忘. 这章中,我们提到的查询界面如下所示: 其中,涉及 ...

  9. TinyFrame升级之十:WCF Rest Service注入IOC的心

    由于在实际开发中,Silverlight需要调用WebService完成数据的获取,由于之前我们一直采用古老的ASMX方式,生成的代理类不仅难以维护,而且自身没有提供APM模式的调用方式,导致在Sin ...

随机推荐

  1. js自执行函数的几种不同写法的比较

    经常需要一个函数自执行,可惜这一种写法是错的: function(){alert(1);}();  原因是前半段“function(){alert(1);}”被当成了函数声明,而不是一个函数表达式,从 ...

  2. (转) 一步一步学习ASP.NET 5 (二)- 通过命令行和sublime创建项目

    转发:微软MVP 卢建晖 的文章,希望对大家有帮助. 注:昨天转发之后很多朋友指出了vNext的命名问题,原文作者已经做出了修改,后面的标题都适用 asp.net 5这个名称. 编者语 : 昨天发了第 ...

  3. JavaScript Patterns 4.10 Curry

    Function Application apply() takes two parameters: the first one is an object to bind to this inside ...

  4. 自动kill慢查询

    在生产环境中,DB服务器经常会被并发的慢查询压挂,因此事前进行sql审核避免烂SQL很重要.万一不小心慢sql还是跑到线上,并且并发还不小,这是dba肯定会收到告警.dba上线处理第一时间是定位并ki ...

  5. Javascript之旅——第十站:为什么都说闭包难理解呢?

    研究过js的朋友大多会说,理解了js的原型和闭包就可以了,然后又说这些都是js的高级内容,然后就又扯到了各种神马的作用域...然后不少 人就会被忽悠的云里雾里...下面我也试着来说说闭包,看我说的这个 ...

  6. 按要求编写Java应用程序: (1)编写西游记人物类(XiYouJiRenWu) 其中属性有:身高(height),名字(name),武器(weapon) 方法有:显示名字(printName),显示武器(printWeapon) (2)在主类的main方法中创建二个对象:zhuBaJie,sunWuKong。并分别为他 们的两个属性(name,weapon)赋值,最后分别调用printName,

    package com.hanqi.test; public class xiyoujirenwu { private double height;// 身高 private String name; ...

  7. Managed DirectX中的DirectShow应用(简单Demo及源码)

    阅读目录 介绍 准备工作 环境搭建 简单Demo 显示效果 其他 Demo下载 介绍 DirectX是Microsoft开发的基于Windows平台的一组API,它是为高速的实时动画渲染.交互式音乐和 ...

  8. 含有SilverLight项目的代码重用

    很多时候,我们工程中不只是有SilverLight项目,然而我们想把其他的项目中的工具类,或者实体类复用到SilverLight项目中时,会发现SilverLight项目无法使用.这是个很普遍的现象. ...

  9. SQL Server调优系列进阶篇(查询语句运行几个指标值监测)

    前言 上一篇我们分析了查询优化器的工作方式,其中包括:查询优化器的详细运行步骤.筛选条件分析.索引项优化等信息. 本篇我们分析在我们运行的过程中几个关键指标值的检测. 通过这些指标值来分析语句的运行问 ...

  10. x01.FileProcessor: 文件处理

    姚贝娜落选,意味着好声音失败.“我们在一起”的精彩亮相,正如同她的歌声,愈唱愈高,直入云霄. 文件处理,无外乎加解密,加解压,分割合并.本着“快舟"精神,花了两天时间,写了个小程序,基本能满 ...