仓储原理:
理解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();
}
}
}