HTML5技术

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

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

DDD 领域驱动设计-谈谈Repository、IUnitOfWork和IDbContext的实践(2) 上一篇:《DDD 领域驱动设计-谈谈 Repository、IUnitOfWork 和 IDbContext 的实践(1)》 阅读目录: 简单总结上篇所做的两个改进: 从 Repository 和 UnitOfWork 中抽离出 IDbConte

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

上一篇:《DDD 领域驱动设计-谈谈 Repository、IUnitOfWork 和 IDbContext 的实践(1)》

阅读目录:

简单总结上篇所做的两个改进:

  • 从 Repository 和 UnitOfWork 中抽离出 IDbContext,并且它们只依赖于 IDbContext。
  • Repository 和 UnitOfWork 为平级关系,UnitOfWork 负责维护对象状态(增删改),Repository 负责获取对象(查)。
  • 后来,园友 Qlin 在评论中,提出了另外一种,大致为:

  • Repository 和 UnitOfWork 还是依赖于 IDbContext。
  • UnitOfWork 只有 Commit,Repository 提供对象的所有操作(增删改查)。
  • 这篇文章我们就按照这种方式实现一下,关于 Repository、IUnitOfWork 和 IDbContext 的设计,以及 Application Service 的调用,上面是两种设计方案,加上上一篇博文开头说到的一种方案,我大致总结了三种,关于它们的优缺点,文章最后我再进行总结。

    另外,关于 IDbContext 的接口设计,其实是有些模糊的,因为它并没有真正解耦 EF,比如 DbSet<TEntity> Set<TEntity>() 还是依赖于 EF,没办法,就像我们在 Repository 中返回 IQueryable,你在 Application Service 调用的时候,也必须引用 EF 一样,对于 IDbContext 来说,我们暂时把它看作是一个数据上下文容器,所有对象的持久化最后都通过它来完成,因为我们的解决方案暂时只能使用 EF,所以对于 IDbContext,我们先暂时这样设计。

    下面我们开始进行设计。

    1. 抽离 IRepository 并改造 Repository

    抽离 IRepository 啥意思?我们直接来看下代码:

    namespace DDD.Sample.Domain.IRepository { public interface IRepository<TAggregateRoot> where TAggregateRoot : class, IAggregateRoot { void Add(TAggregateRoot aggregateRoot); void Update(TAggregateRoot aggregateRoot); void Delete(TAggregateRoot aggregateRoot); TAggregateRoot Get(int id); } }

    IRepository 是一个泛型接口,类型为 IAggregateRoot,我们在里面定义了增删改查的常用操作,它的作用就是减少 Repository 的冗余代码,我们看下 IStudentRepository 的定义:

    namespace DDD.Sample.Domain.IRepository { public interface IStudentRepository : IRepository<Student> { Student GetByName(string name); } }

    IStudentRepository 需要继承 IRepository,并确定泛型类型为 Student,Student 继承自 IAggregateRoot,因为增删改查常用操作已经定义,所以我们在其它类似的 IStudentRepository 中就不需要定义了。

    IRepository 需要进行实现,如果在 StudentRepository 中进行实现,就没有什么作用了,所以我们需要一个 BaseRepository 来实现 IRepository:

    namespace DDD.Sample.Repository { public abstract class BaseRepository<TAggregateRoot> : IRepository<TAggregateRoot> where TAggregateRoot : class, IAggregateRoot { public readonly IDbContext _dbContext; public BaseRepository(IDbContext dbContext) { _dbContext = dbContext; } public void Add(TAggregateRoot aggregateRoot) { _dbContext.Set<TAggregateRoot>().Add(aggregateRoot); } public void Update(TAggregateRoot aggregateRoot) { _dbContext.Entry<TAggregateRoot>(aggregateRoot).State = EntityState.Modified; } public void Delete(TAggregateRoot aggregateRoot) { _dbContext.Set<TAggregateRoot>().Remove(aggregateRoot); } public TAggregateRoot Get(int id) { return _dbContext.Set<TAggregateRoot>().FirstOrDefault(t => t.Id == id); } } }

    咋一看 BaseRepository 有点像我们上篇的 UnitOfWork,因为我们把增删改放在 Repository 了,因为 Repository 还是和 UnitOfWork 为平级关系,所以我们在 Repository 中用的 IDbContext 而非 IUnitOfWork,这个没什么问题,我们看下 StudentRepository 的具体实现:

    namespace DDD.Sample.Repository { public class StudentRepository : BaseRepository<Student>, IStudentRepository { public StudentRepository(IDbContext dbContext) : base(dbContext) { } public Student GetByName(string name) { return base._dbContext.Set<Student>().Where(x => x.Name == name).FirstOrDefault(); } } }

    StudentRepository 很简单,因为常用操作 BaseRepository 已经实现了,base(dbContext) 的作用就是给 BaseRepository 注入 IDbContext 对象。

    Repository 的改造基本上就这些,表面看起来确实很好,另外,如果没有 IUnitOfWork 和 Application Service,我们对 Domain 进行单元测试,也是能满足我们的需求,但需要将 IDbContext 再进行修改下。

    2. IUnitOfWork 和 Application Service 的变化

    我们先看下 IUnitOfWork 的变化,直接贴下代码:

    namespace DDD.Sample.Infrastructure.Interfaces { public interface IUnitOfWork { bool Commit(); void Rollback(); } }

    因为增删改都移到 Repository 中了,所以 IUnitOfWork 的工作就很简单,只有 Commit 和 Rollback,实现也比较简单,我们看下:

    namespace DDD.Sample.Infrastructure { public class UnitOfWork : IUnitOfWork { private IDbContext _dbContext; public UnitOfWork(IDbContext dbContext) { _dbContext = dbContext; } public bool Commit() { return _dbContext.SaveChanges() > 0; } public void Rollback() { throw new NotImplementedException(); } } }

    这个没啥说的,我们直接看下 Application Service 的代码:

    namespace DDD.Sample.Application { public class StudentService : IStudentService { private IUnitOfWork _unitOfWork; private IStudentRepository _studentRepository; private ITeacherRepository _teacherRepository; public StudentService(IUnitOfWork unitOfWork, IStudentRepository studentRepository, ITeacherRepository teacherRepository) { _unitOfWork = unitOfWork; _studentRepository = studentRepository; _teacherRepository = teacherRepository; } public Student Get(int id) { return _studentRepository.Get(id); } public bool Add(string name) { var student = new Student { Name = name }; var teacher = _teacherRepository.Get(1); teacher.StudentCount++; _studentRepository.Add(student); _teacherRepository.Update(teacher); return _unitOfWork.Commit(); } } }

     

    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

    网友点评
    t