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

    本章源码下载:

    点击这里下载

    备份下载地址

  • 相关阅读:
    HDU2602:Bone Collector
    HDU5773:The All-purpose Zero
    LightOJ 1275:Internet Service Providers
    8.SpringMVC拦截器
    7.SpringMVC和Ajax技术
    Tomcat什么时候需要restart,redeploy,update classes and resources
    6.SpringMVC的JSON讲解
    5.SpringMVC数据处理
    4.SpringMVC的结果跳转方式
    3.SpringMVC的Controller 及 RestFul风格
  • 原文地址:https://www.cnblogs.com/scy251147/p/3671213.html
Copyright © 2011-2022 走看看