1)领域层不应该直接依赖于仓储实现:如果领域层依赖于仓储实现,一是技术绑定太紧密,二是仓储要对领域对象作操作,会造成循环依赖。
2)将接口定义在领域层,减少技术架构依赖,应用层或领域层要使用某个仓储实现时,通过依赖注入的方式将仓储实现注射到应用层或领域层,具体IOC在使用时对应用层与领域层的建议见前面的文章。
定义IRepositoryContext接口的主要目的是:因为我们采用的持久化机制是EF,EF是通过DBContext来管理数据操作的事务,一般是针对单实体的。通常我们的业务需要持久化整个聚合的多个实体或通过领域服务或应用服务持久化多个聚合,多个实体或聚合在业务上需要保持一致性,为了达到这个目的,我们引入了工作单元模式与定义了仓储上下文,通过仓储上下文来管理操作的多个实体或多个聚合中的实体,然后通过工作单元模式统一提交来保证事务,从而保证业务的一致性。
IDbContext -> IUnitOfWork(only commit)/IRepository -> UnitOfWork/Repository -> Application Service 方案
using DDD.Sample.Application.Interfaces; using DDD.Sample.Domain; using DDD.Sample.Domain.IRepository; using DDD.Sample.Infrastructure; using DDD.Sample.Infrastructure.Interfaces; using DDD.Sample.Repository; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Data.Entity; using EntityFramework.Extensions; 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 async Task<Student> Get(int id) { return await _studentRepository.Get(id).FirstOrDefaultAsync(); } public async Task<bool> Add(string name) { var student = new Student { Name = name }; var teacher = await _teacherRepository.Get(1).FirstOrDefaultAsync(); teacher.StudentCount++; _unitOfWork.RegisterNew(student); _unitOfWork.RegisterDirty(teacher); return await _unitOfWork.CommitAsync(); } public async Task<bool> UpdateName(int id, string name) { return await _studentRepository.Get(id) .UpdateAsync(x => new Student { Name = name }) > 0; } } }