HTML5技术

DDD 领域驱动设计-谈谈 Repository、IUnitOfWork 和 IDbContext 的实践 - 田园里的(2)

字号+ 作者:H5之家 来源:博客园 2015-10-16 10:29 我要评论( )

EfUnitOfWork 继承 DbContext 和 IUnitOfWork,使用 EF 作为对象管理和持久化,这样实现好像没有什么问题,我们一般也是这样做的,其实,这是一个坑,我们后面会讲到,另外,之前说到 EF 中有 SaveChanges,为什么

EfUnitOfWork 继承 DbContext 和 IUnitOfWork,使用 EF 作为对象管理和持久化,这样实现好像没有什么问题,我们一般也是这样做的,其实,这是一个坑,我们后面会讲到,另外,之前说到 EF 中有 SaveChanges,为什么还有包裹一层 IUnitOfWork?其实就是说的上面代码,因为所有的 IUnitOfWork 的实现,我们都是使用的 EF,既然如此,为啥不把 IUnitOfWork 这个空壳拿掉呢?有人会说了,IUnitOfWork 是 DDD 中的概念,巴拉巴拉,不能拿掉,要不然就不是 DDD 了呢?

上面的问题先放在这个,如果 EfUnitOfWork 这样实现 IUnitOfWork,那 Repository 会怎样?看下面的代码:

public class StudentRepository: IStudentRepository { private IQueryable<Student> _students; public StudentRepository(IUnitOfWork unitOfWork) { _students = unitOfWork.Set<Student>();//没有了之前的 Set<TEntity>(),咋办啊??? } public Student Get(int id) { return _students.Where(x => x.Id == id).FirstOrDefault(); } //.... }

代码进行到这,突然进行不下去了,咋办呢?如果你回过头去修改 IUnitOfWork 的接口,比如增加 Set<TEntity>(),这时候将又回到开始的问题,一切将前功尽弃,这么解决呢?这时候要停下来,思考 Repository 和 IUnitOfWork 的关系,也就是之前提到的,它们俩有关系么???

IUnitOfWork 的定义上面说过了,我们再看下 Repository 的定义:

  • Repository:协调领域和数据映射层,利用类似于集合的接口来访问领域对象。
  • 重点在于访问,Repository 是用来访问领域对象的,所以,之前我们在 IRepository 中定义 Add、Update、Renove 等等接口,我觉得这些不是很恰当,因为对象列表的更改,我们可以用 IUnitOfWork 记录和实现,Repository 和 IUnitOfWork 应该是平级的概念,如果在 Repository 中去使用 IUnitOfWork,就有点违背其定义了。

    IUnitOfWork 有其 EfUnitOfWork 的实现,难道我们还要搞一个 IRepository 对应的 EfRepository 实现?很显然,如果这样设计是非常冗余的,这时候,你是不是想到了我们还没有提到的 IDbContext 呢???没错就是它,让 UnitOfWork 和 Repository 都依赖于 IDbContext,而不是依赖于具体的 EF,这样也就没有了之前一直提到的 UnitOfWork 和 EF 的问题,具体怎么做呢?我们得先定义 IDbContext:

    public interface IDbContext { DbSet<TEntity> Set<TEntity>() where TEntity : class; DbEntityEntry<TEntity> Entry<TEntity>(TEntity entity) where TEntity : class; int SaveChanges(); }

    IDbContext 的作用,就是提供对象列表的一切操作接口,接下来实现一个 SchoolDbContext:

    public class SchoolDbContext : DbContext, IDbContext { public SchoolDbContext() : base("name=db_school") { } protected override void OnModelCreating(DbModelBuilder modelBuilder) { modelBuilder.Entity<Student>(); modelBuilder.Entity<Teacher>(); base.OnModelCreating(modelBuilder); } }

    SchoolDbContext 有点像我们之前的 EfUnitOfWork,但它和 IUnitOfWork 没有任何关系,它的作用就是提供具体的对象持久化和访问,我们一般会放在 Infrastructure 层。另外,可以看到 SchoolDbContext 似乎并没有实现 IDbContext 的接口,为什么呢?因为我们继承了 DbContext,这些接口都在 DbContext 中进行进行实现了,你可以按 F12 进行查看。

    接下来我们要对 EfUnitOfWork 进行改造了,IUnitOfWork 和 EF 已经没有半毛钱关系了,所以我们命名直接去掉 Ef,具体实现代码:

    public class UnitOfWork : IUnitOfWork { private IDbContext _dbContext; public UnitOfWork(IDbContext dbContext) { _dbContext = dbContext; } public void RegisterNew<TEntity>(TEntity entity) where TEntity : class { _dbContext.Set<TEntity>().Add(entity); } public void RegisterDirty<TEntity>(TEntity entity) where TEntity : class { _dbContext.Entry<TEntity>(entity).State = EntityState.Modified; } public void RegisterClean<TEntity>(TEntity entity) where TEntity : class { _dbContext.Entry<TEntity>(entity).State = EntityState.Unchanged; } public void RegisterDeleted<TEntity>(TEntity entity) where TEntity : class { _dbContext.Set<TEntity>().Remove(entity); } public bool Commit() { return _dbContext.SaveChanges() > 0; } public void Rollback() { throw new NotImplementedException(); } }

    UnitOfWork 脱离了 EF, 是不是有种小清新的感觉?UnitOfWork 依赖于 IDbContext,所以,UnitOfWork 并不关心用哪种具体技术进行实现,你只需要给我对象访问和持久化接口就可以了,下面再看一下之前进行不下去的 Repository:

    public class StudentRepository: IStudentRepository { private IQueryable<Student> _students; public StudentRepository(IDbContext dbContext) { _students = dbContext.Set<Student>(); } public Student Get(int id) { return _students.Where(x => x.Id == id).FirstOrDefault(); } }

     

    1.本站遵循行业规范,任何转载的稿件都会明确标注作者和来源;2.本站的原创文章,请转载时务必注明文章作者和来源,不尊重原创的行为我们将追究责任;3.作者投稿可能会经我们编辑修改或补充。

    相关文章
    • 设计模式(1)单例模式(Singleton) - Fonour

      设计模式(1)单例模式(Singleton) - Fonour

      2017-04-23 12:00

    • 架构设计师能力模型 - BloodyAngel

      架构设计师能力模型 - BloodyAngel

      2017-03-28 11:00

    • 设计模式(0)简单工厂模式 - Fonour

      设计模式(0)简单工厂模式 - Fonour

      2017-03-25 15:01

    • 没有功能需求设计文档?对不起,拒绝开发! - CharlieChu

      没有功能需求设计文档?对不起,拒绝开发! - CharlieChu

      2017-03-16 13:04

    网友点评
    =