zoukankan      html  css  js  c++  java
  • TinyFrame升级之七:重构Repository和Unit Of Work

    首先,重构的想法来源于以下文章: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的理解:

    QQ截图20140417170836

    本章源码下载:

    点击这里下载

    备份下载地址

  • 相关阅读:
    Windows SDK编程(Delphi版) 之 应用基础,楔子
    一个小问题引发的论证思考
    Delphi 组件开发教程指南(7)继续模拟动画显示控件
    用PyInstaller将python转成可执行文件exe笔记
    使用 .Net Memory Profiler 诊断 .NET 应用内存泄漏(方法与实践)
    Microsof Office SharePoint 2007 工作流开发环境搭建
    How to monitor Web server performance by using counter logs in System Monitor in IIS
    LINQ之Order By
    window 性能监视器
    内存泄露检测工具
  • 原文地址:https://www.cnblogs.com/scy251147/p/3671213.html
Copyright © 2011-2022 走看看