倉儲原理:
理解Repository(下文簡稱倉儲)和Unit of Work(下文簡稱工作單元)模式
倉儲(Repository)模式自2004年首次作為領域驅動模型DDD設計的一部分引入,倉儲本質上是提供提供數據的抽象,以便應用程序可以使用具有接口的相似的簡單抽象集合。從此集合中CURD是通過一些列直接的方法完成,無需處理連接、命令等問題,使用此種模式可幫助實現松耦合,並保持領域對象的持久性無知。
- 倉儲模式是為了在程序的數據訪問層和業務邏輯層之間創建的一個抽象層
- 倉儲模式是一種數據訪問模式,提供一種更松散耦合的數據訪問方法
- 將創建數據訪問的邏輯寫在單獨的類中即倉儲
- 倉儲負責和業務層進行持久化通信
倉儲(Repository)是存在於工作單元和數據庫之間單獨分離出來的一層,是對數據訪問的封裝。其優點是
- 業務層無需知道具體實現達到分離關注點
- 提高對數據庫訪問的維護,對於倉儲的改變並不改變業務的邏輯。
如何處理多個Repository庫?
下面想象下如下場景,我們數據庫中有多個表,那樣我們需要為每個表創建一個Reporsitory類。(好多重復工作的說,其實這不是問題)
為什么每個Repository要擁有一個數據上下文的實例呢?為什么不在一些地方創建一個它的實例,然后在repository被實例化的時候作為參數傳遞進去呢。現在這個新的類被命名為 UnitOfWork ,此類將負責創建數據上下文實例並移交到控制器的所有repository實例。
通用倉儲和工作單元
public IRepository<T> Repository<T>() where T : class { if (repositories.Keys.Contains(typeof(T)) == true) { return repositories[typeof(T)] as IRepository<T>; } IRepository<T> repo=new GenericRepository<T>(dbContext); repositories.Add(typeof(T), repo); return repo; }
這樣我們就可以不用一個一個去創建repository 用工作單元管理
可以用此方法改進以下代碼 不用一個一個表創建repository
目錄
IRepository
- IBaseRepository
public interface IBaseRepository<T> where T : class, new() { ValueTask<EntityEntry<T>> Insert(T entity); void Update(T entity); Task<int> Update(Expression<Func<T, bool>> whereLambda, Expression<Func<T, T>> entity); Task<int> Delete(Expression<Func<T, bool>> whereLambda); Task<bool> IsExist(Expression<Func<T, bool>> whereLambda); Task<T> GetEntity(Expression<Func<T, bool>> whereLambda); Task<List<T>> Select(); Task<List<T>> Select(Expression<Func<T, bool>> whereLambda); Task<Tuple<List<T>, int>> Select<S>(int pageSize, int pageIndex, Expression<Func<T, bool>> whereLambda, Expression<Func<T, S>> orderByLambda, bool isAsc); }
- IUnitOfWork
public interface IUnitOfWork { MyDbContext GetDbContext(); Task<int> SaveChangesAsync(); }
- IStudentRepository
public interface IStudentRepository : IBaseRepository<Student> { }
Repository
- BaseRepository
public class BaseRepository<T> where T : class, new() { private readonly MyDbContext myDbContext; public BaseRepository(MyDbContext myDbContext) { this.myDbContext = myDbContext; } public async ValueTask<EntityEntry<T>> Insert(T entity) { return await myDbContext.Set<T>().AddAsync(entity); } public void Update(T entity) { myDbContext.Set<T>().Update(entity); } public async Task<int> Update(Expression<Func<T, bool>> whereLambda, Expression<Func<T, T>> entity) { return await myDbContext.Set<T>().Where(whereLambda).UpdateAsync(entity); } public async Task<int> Delete(Expression<Func<T, bool>> whereLambda) { return await myDbContext.Set<T>().Where(whereLambda).DeleteAsync(); } public async Task<bool> IsExist(Expression<Func<T, bool>> whereLambda) { return await myDbContext.Set<T>().AnyAsync(whereLambda); } public async Task<T> GetEntity(Expression<Func<T, bool>> whereLambda) { return await myDbContext.Set<T>().AsNoTracking().FirstOrDefaultAsync(whereLambda); } public async Task<List<T>> Select() { return await myDbContext.Set<T>().ToListAsync(); } public async Task<List<T>> Select(Expression<Func<T, bool>> whereLambda) { return await myDbContext.Set<T>().Where(whereLambda).ToListAsync(); } public async Task<Tuple<List<T>, int>> Select<S>(int pageSize, int pageIndex, Expression<Func<T, bool>> whereLambda, Expression<Func<T, S>> orderByLambda, bool isAsc) { var total = await myDbContext.Set<T>().Where(whereLambda).CountAsync(); if (isAsc) { var entities = await myDbContext.Set<T>().Where(whereLambda) .OrderBy<T, S>(orderByLambda) .Skip(pageSize * (pageIndex - 1)) .Take(pageSize).ToListAsync(); return new Tuple<List<T>, int>(entities, total); } else { var entities = await myDbContext.Set<T>().Where(whereLambda) .OrderByDescending<T, S>(orderByLambda) .Skip(pageSize * (pageIndex - 1)) .Take(pageSize).ToListAsync(); return new Tuple<List<T>, int>(entities, total); } } }
- UnitOfWork
public class UnitOfWork : IUnitOfWork { private readonly MyDbContext myDbContext; public UnitOfWork(MyDbContext myDbContext) { this.myDbContext = myDbContext; } public MyDbContext GetDbContext() { return myDbContext; } public async Task<int> SaveChangesAsync() { return await myDbContext.SaveChangesAsync(); } }
- StudentRepository
public class StudentRepository : BaseRepository<Student>, IStudentRepository { public StudentRepository(MyDbContext myDbContext) : base(myDbContext) { } }
IService
- IBaseService
public interface IBaseService<T> where T : class, new() { Task<int> Insert(T entity); Task<int> Update(T entity); Task<int> Update(Expression<Func<T, bool>> whereLambda, Expression<Func<T, T>> entity); Task<int> Delete(Expression<Func<T, bool>> whereLambda); Task<bool> IsExist(Expression<Func<T, bool>> whereLambda); Task<T> GetEntity(Expression<Func<T, bool>> whereLambda); Task<List<T>> Select(); Task<List<T>> Select(Expression<Func<T, bool>> whereLambda); Task<Tuple<List<T>, int>> Select<S>(int pageSize, int pageIndex, Expression<Func<T, bool>> whereLambda, Expression<Func<T, S>> orderByLambda, bool isAsc); }
- IStudentService
public interface IStudentService : IBaseService<Student> { Task<bool> UOW(Student student, Teacher teacher); }
Service
- BaseService
public class BaseService<T> where T : class, new() { protected IUnitOfWork unitOfWork; protected IBaseRepository<T> currentRepository; public BaseService(IUnitOfWork unitOfWork, IBaseRepository<T> currentRepository) { this.unitOfWork = unitOfWork; this.currentRepository = currentRepository; } public async Task<int> Insert(T entity) { await currentRepository.Insert(entity); return await unitOfWork.SaveChangesAsync(); } public async Task<int> Update(T entity) { currentRepository.Update(entity); return await unitOfWork.SaveChangesAsync(); } public async Task<int> Update(Expression<Func<T, bool>> whereLambda, Expression<Func<T, T>> entity) { await currentRepository.Update(whereLambda, entity); return await unitOfWork.SaveChangesAsync(); } public async Task<int> Delete(Expression<Func<T, bool>> whereLambda) { await currentRepository.Delete(whereLambda); return await unitOfWork.SaveChangesAsync(); } public async Task<bool> IsExist(Expression<Func<T, bool>> whereLambda) { return await currentRepository.IsExist(whereLambda); } public async Task<T> GetEntity(Expression<Func<T, bool>> whereLambda) { return await currentRepository.GetEntity(whereLambda); } public async Task<List<T>> Select() { return await currentRepository.Select(); } public async Task<List<T>> Select(Expression<Func<T, bool>> whereLambda) { return await currentRepository.Select(whereLambda); } public async Task<Tuple<List<T>, int>> Select<S>(int pageSize, int pageIndex, Expression<Func<T, bool>> whereLambda, Expression<Func<T, S>> orderByLambda, bool isAsc) { return await currentRepository.Select(pageSize, pageIndex, whereLambda, orderByLambda, isAsc); } }
- StudentService
public class StudentService : BaseService<Student>, IStudentService { private readonly ITeacherRepository teacherRepository; public StudentService(IUnitOfWork unitOfWork, IBaseRepository<Student> currentRepository, ITeacherRepository teacherRepository) : base(unitOfWork, currentRepository) { this.teacherRepository = teacherRepository; } public async Task<bool> UOW(Student student, Teacher teacher) { await currentRepository.Insert(student); await teacherRepository.Insert(teacher); await unitOfWork.SaveChangesAsync(); return true; } }
Controller
- StudentController
[Route("api/[controller]/[action]")] [ApiController] public class StudentController : ControllerBase { private readonly IStudentService studentService; public StudentController(IStudentService studentService) { this.studentService = studentService; } [HttpPost] public async Task<string> Insert([FromForm] Student student) { try { await studentService.Insert(student); return new Response().ToJson(); } catch (Exception e) { return new Response() { Code = 500, Message = e.Message }.ToJson(); } } [HttpPost] public async Task<string> Update([FromForm] Student student) { try { //await studentService.Update(student); await studentService.Update(t => t.Sid == student.Sid, t => new Student() { Sage = student.Sage }); return new Response().ToJson(); } catch (Exception e) { return new Response() { Code = 500, Message = e.Message }.ToJson(); } } [HttpPost] public async Task<string> Delete(int id) { try { await studentService.Delete(t => t.Sid == id); return new Response().ToJson(); } catch (Exception e) { return new Response() { Code = 500, Message = e.Message }.ToJson(); } } [HttpGet] public async Task<string> Select() { try { var students = await studentService.Select(t => true); return new Response<Student>() { Data = students }.ToJson(); } catch (Exception e) { return new Response() { Code = 500, Message = e.Message }.ToJson(); } } [HttpPost] public async Task<string> UOW([FromForm] Student student) { try { Teacher teacher = new Teacher() { Tid = student.Sid, Tname = student.Sname }; await studentService.UOW(student, teacher); return new Response().ToJson(); } catch (Exception e) { return new Response() { Code = 500, Message = e.Message }.ToJson(); } } }