HTML5技术

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

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

DDD 领域驱动设计-谈谈 Repository、IUnitOfWork 和 IDbContext 的实践 好久没写 DDD 领域驱动设计相关的文章了,嘎嘎!!! 这几天在开发一个新的项目,虽然不是基于领域驱动设计的,但我想把 DDD 架构设计的一些东西运用在上面,但发现了很多问题,这些在

DDD 领域驱动设计-谈谈 Repository、IUnitOfWork 和 IDbContext 的实践

好久没写 DDD 领域驱动设计相关的文章了,嘎嘎!!!

这几天在开发一个新的项目,虽然不是基于领域驱动设计的,但我想把 DDD 架构设计的一些东西运用在上面,但发现了很多问题,这些在之前的短消息项目中也有,比如我一直想重构短消息 Repository 实现的一些东西,但之前完全没有头绪,因为内部的实现错综复杂,牵一发而动全身,不知道从哪下手。

正好这次新项目的开发,让我一步一步代码设计,所以之前疑惑的问题,可以很清晰的分析并解决,解决问题的过程最终形成了一个 DDD 框架示例,大家可以参考下:

开源地址:https://github.com/yuezhongxin/DDD.Sample

一点一滴-疑惑出现

疑惑就是 Repository 和 IUnitOfWork,以及 Application Service 的调用,这样说可能很笼统,其实就是这三者如何更好的结合使用?并且让它们各司其职,发挥出自己的最大作用,下面我举个例子,可能大家更好理解一些。

首先,关于 IUnitOfWork 的定义实现,网上我搜了很多,很多都太一样,比如有人这样定义:

public interface IUnitOfWork { IQueryable<TEntity> Set<TEntity>() where TEntity : class; TEntity Add<TEntity>(TEntity entity) where TEntity : class; TEntity Attach<TEntity>(TEntity entity) where TEntity : class; TEntity Remove<TEntity>(TEntity entity) where TEntity : class; void Commit(); void Rollback(); IDbContext Context { get; set; }//也有人添加这个 }

是不是感觉有点像 EF 中的 DbContext 呢?所以这也是一个疑惑点,IUnitOfWork 和 DbContext 是什么关系?比如有很多人疑惑:EF 中有 SaveChanges,为什么还有包裹一层 IUnitOfWork?这个问题之前已经讨论了无数次,但这些都是纸上进行的,如果你实践起来可能会是另一种感受。

如果 IUnitOfWork 按照上面的代码进行设计,那 Repository 会是什么样的呢?我们来看一下:

public class StudentRepository: IStudentRepository { private IUnitOfWork _unitOfWork; public StudentRepository(IUnitOfWork unitOfWork) { _unitOfWork = unitOfWork; } public Student Get(int id) { return _unitOfWork.Set<Student>().Where(x => x.Id == id).FirstOrDefault(); } public void Add(Student student) { return _unitOfWork.Set<Student>().Add(student); } //.... }

上面是 Repository 的一种设计,也有人会这样定义:private IQueryable<Student> _students;,然后在 StudentRepository 构造函数中进行赋值,但不管怎么设计,我们一般会将 Repository 和 IUnitOfWork 结合起来使用,这是一个重要的疑惑点:Repository 和 IUnitOfWork 真的有关系么???

另外,关于 Repository 返回 IQueryable?还是 IEnumerable?可以参考之前的一篇博文,这里我采用的是“概念上的合理”,即 Not IQueryable。

如果 Repository 按照上面的代码进行设计,那 Application Service 会是什么样的呢?我们来看一下:

public class StudentService : IStudentService { private IUnitOfWork _unitOfWork; private IStudentRepository _studentRepository; public StudentService(IUnitOfWork unitOfWork, IStudentRepository studentRepository) { _unitOfWork = unitOfWork; _studentRepository = studentRepository; } public Student Get(int id) { //return _unitOfWork.Set<Student>().Where(x => x.Id == id).FirstOrDefault(); return _studentRepository.Get(id); } public bool Add(Student student) { //_unitOfWork.Add<Student>(student); _studentRepository.Add(student); return _unitOfWork.Commit(); } //.... }

看到上面的代码,我想你应该明白到底疑惑什么了?在 StudentService 中,StudentRepository 似乎变得有些多余,因为它所做的,UnitOfWork 也都可以做,随着项目的复杂,这样就会造成很多的问题,比如:

一步一步-分析解决

其实问题是可以进行溯源,如果一开始的设计变的很糟,那么接下来相关的其它设计,也会变的很糟,我们可以发现,上面出现问题的根源,其实就是一开始 IUnitOfWork 的设计问题,网上有关 IUnitOfWork 的设计实现,简直五花八门,那我们应该相信谁呢?我们应该相信一开始关于 IUnitOfWork 的定义:

  • Unit of Work:维护受业务事务影响的对象列表,并协调变化的写入和并发问题的解决。工作单元记录在业务事务过程中对数据库有影响的所有变化,操作结束后,作为一种结果,工作单元了解所有需要对数据库做的改变,统一对数据库操作。
  • 上面的文字定义要结合 IUnitOfWork 图中的实现,可以更好的理解一些。

    我们发现,它和我们一开始的定义差别很大,比如:IQueryable<TEntity> Set<TEntity>() 这样的定义实现,如果结合上面的定义就不是很恰当,IUnitOfWork 是记录业务事务过程中对象列表的改变,平常我们所说对数据的增删改查,你可以理解为 IUnitOfWork 和增删改有关,和查询不太相关。

    所以,我们完全按照定义,再重新实现一次 IUnitOfWork:

    public interface IUnitOfWork { void RegisterNew<TEntity>(TEntity entity) where TEntity : class; void RegisterDirty<TEntity>(TEntity entity) where TEntity : class; void RegisterClean<TEntity>(TEntity entity) where TEntity : class; void RegisterDeleted<TEntity>(TEntity entity) where TEntity : class; bool Commit(); void Rollback(); }

    你可以看到,我们完全按照定义进行实现的,甚至是接口名字都一样,下面我们看一下 IUnitOfWork 的具体实现:

    public class EfUnitOfWork : DbContext, IUnitOfWork { public EfUnitOfWork() : base("name=db_school") { } protected override void OnModelCreating(DbModelBuilder modelBuilder) { modelBuilder.Entity<Student>(); modelBuilder.Entity<Teacher>(); base.OnModelCreating(modelBuilder); } public void RegisterNew<TEntity>(TEntity entity) where TEntity : class { base.Set<TEntity>().Add(entity); } public void RegisterDirty<TEntity>(TEntity entity) where TEntity : class { base.Entry<TEntity>(entity).State = EntityState.Modified; } public void RegisterClean<TEntity>(TEntity entity) where TEntity : class { base.Entry<TEntity>(entity).State = EntityState.Unchanged; } public void RegisterDeleted<TEntity>(TEntity entity) where TEntity : class { base.Set<TEntity>().Remove(entity); } public bool Commit() { return base.SaveChanges() > 0; } public void Rollback() { throw new NotImplementedException(); } }

     

    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

    网友点评