首先,重构的想法来源于以下文章: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. 1: public virtual void Insert(T entity)
  1. 2: {
  1. 3: try
  1. 4: {
  1. 5: if (entity == null)
  1. 6: throw new ArgumentException("实体类为空");
  1. 7: DbSet.Add(entity);
  1. 8: context.SaveChanges();
  1. 9: }
  1. 10: catch (DbEntityValidationException dbex)
  1. 11: {
  1. 12: var msg = string.Empty;
  1. 13: foreach(var validationErrors in dbex.EntityValidationErrors)
  1. 14: foreach(var validateionError in validationErrors.ValidationErrors)
  1. 15: msg+=string.Format("Property:{0} Error:{1}",validateionError.PropertyName,validateionError.ErrorMessage);
  1. 16:  
  1. 17: var fail = new Exception(msg,dbex);
  1. 18: throw fail;
  1. 19: }
  1. 20: }

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

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

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

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

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

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

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

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

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

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

1.提供全局事务支持。

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

下面是代码重构部分:

IUnitOfWork接口部分:

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

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

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

    摘要: CMMI有计划(PP)及计划跟踪(PMC)两个PA,而某一个PA又有GP2.2计划及GP2.8计划跟踪两个GP,看上去是挺“神奇”也挺让人“困惑”的事情. 正文: GP2.2 Establis ...

  2. WPF学习之路(十一)布局

    布局 Canvas 基本面板,传统布局方式,支持与设备无关的坐标定位元素 <Border BorderThickness="> <Canvas> <Button ...

  3. XML 在SQLServer中的使用

    SQL Server对于XML支持的核心在于XML数据的格式,这种数据类型可以将XML的数据存储于数据库的对象中,比如variables, columns, and parameters.当你用XML ...

  4. 编写IoDemo.java的Java应用程序,程序完成的功能是:首先读取text.txt文件内容,再通过键盘输入文件的名称为iodemo.txt,把text.txt的内容存入iodemo.txt

    package zuoye; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundExcep ...

  5. Mycat实现读写分离,主备热切换

    实验环境:ubutu server 14 Master IP:172.16.34.212 Slave IP:172.16.34.34.156 Mycat server IP:172.16.34.219 ...

  6. nginx参数说明

    一.nginx的核心配置: >>> 正常运行的必备配置: 1. user username [groupname]; #指定运行worker子进程的用户或组 2. pid /path ...

  7. nodeJS Express 删除 x-powered-by

    在使用Express4 Header头部会输出,在晚上搜索几种方案也没有产生效果,就看了一下官方文档 Property Type               Value Default     x-p ...

  8. PDO链接mysql学习笔记

    <?php //PDO链接mysql//dsn三种写法: //dsn01 $dsn = 'mysql:host=localhost;dbname=mysql'; //$dsn = 'mysql: ...

  9. 理解 OpenStack + Ceph (7): Ceph 的基本操作和常见故障排除方法

    本系列文章会深入研究 Ceph 以及 Ceph 和 OpenStack 的集成: (1)安装和部署 (2)Ceph RBD 接口和工具 (3)Ceph 物理和逻辑结构 (4)Ceph 的基础数据结构 ...

  10. C#基础---IComparable用法,实现List<T>.sort()排序

    List<T>.sort()可以实现对T的排序,比如List<int>.sort()执行后集合会按照int从小到大排序.如果T是一个自定义的Object,可是我们想按照自己的方 ...