为什么要使用泛型仓储?好处是?
前两章在autofac注入的时候,用的User类作为例子,写了增删改查四个接口,也就是仓储的GRUD。
当我们再添加一个实体(比如Student)时,StudentRepository跟UserRepository代码几乎一样的代码,重复量很大,为了减少冗余、提高工作效率,使用泛型仓储最好不过了
好处:
减少代码冗余
提高了开发人员的工作效率
提高对数据库访问的维护
一、泛型仓储接口和泛型仓储实现类
泛型仓储接口
在类库项目上右键->添加->新建文件夹,命名为Repository,存放泛型仓储类。在Repository文件夹下面新建 泛型仓储接口类:IRepository,如下:
using System; using System.Collections.Generic; using System.Linq; using System.Linq.Expressions; using NetCoreWebApi.Repository.Dto; namespace NetCoreWebApi.Repository.Repository { public interface IRepositorywhere T : class { /// /// 添加实体(单个) /// /// 实体对象 int Add(T entity); /// /// 批量插入实体(多个) /// /// 实体列表 int AddRange(List list); /// /// 删除实体(单个) /// /// int Remove(T entity); /// /// 批量删除实体(多个) /// /// 实体列表 int RemoveRange(List list); /// /// 获取所有 /// /// IQueryable GetAll(); /// /// 分页条件查询 /// /// 排序类型 /// 当前页 /// 每页大小 /// 条件表达式 /// 是否升序排列 /// 排序表达式 /// Page SearchFor (int pageIndex, int pageSize, Expression bool>> predicate, bool isAsc, Expression > keySelector); /// /// 获取实体(主键) /// /// 主键id /// T GetModelById(object id); /// /// 获取实体(条件) /// /// 条件表达式 /// T GetModel(Expression bool>> predicate); /// /// 查询记录数 /// /// 条件表达式 /// 记录数 int Count(Expression bool>> predicate); /// /// 是否存在 /// /// 查询表达式 /// 布尔值 bool Exist(Expression bool>> anyLambda); } }
泛型仓储实现类
在Repository文件夹下面新建 泛型仓储实现类:Repository,并继承IRepository,如下:
using System; using System.Collections.Generic; using System.Linq; using System.Linq.Expressions; using Microsoft.EntityFrameworkCore; using NetCoreWebApi.Model; using NetCoreWebApi.Repository.Dto; namespace NetCoreWebApi.Repository.Repository { public class Repository: IRepository where T : class { private readonly MyDbContext _dbContext; private DbSet _entity; /// /// 构造函数 /// /// public Repository(MyDbContext dbContext) { _dbContext = dbContext; } private DbSet Entity => _entity ?? (_entity = _dbContext.Set ()); /// /// 添加实体(单个) /// /// 实体对象 public int Add(T entity) { Entity.Add(entity); return _dbContext.SaveChanges(); } /// /// 批量插入实体(多个) /// /// 实体列表 public int AddRange(List list) { Entity.AddRange(list); return _dbContext.SaveChanges(); } /// /// 删除实体(单个) /// /// public int Remove(T entity) { Entity.Remove(entity); return _dbContext.SaveChanges(); } /// /// 批量删除实体(多个) /// /// 实体列表 public int RemoveRange(List list) { Entity.RemoveRange(list); return _dbContext.SaveChanges(); } /// /// 获取所有 /// /// public IQueryable GetAll() { return Entity.AsQueryable().AsNoTracking(); } /// /// 条件查询 /// /// 排序类型 /// 当前页 /// 每页大小 /// 是否升序排列 /// 条件表达式 /// 排序表达式 /// public Page SearchFor (int pageIndex, int pageSize, Expression bool>> predicate, bool isAsc, Expression > keySelector) { if (pageIndex <= 0 || pageSize <= 0) throw new Exception("pageIndex或pageSize不能小于等于0"); var page = new Page { PageIndex = pageIndex, PageSize = pageSize }; var skip = (pageIndex - 1) * pageSize; var able = Entity.AsQueryable().AsNoTracking(); if (predicate == null) { var count = Entity.Count(); var query = isAsc ? able.OrderBy(keySelector).Skip(skip).Take(pageSize) : able.OrderByDescending(keySelector).Skip(skip).Take(pageSize); page.TotalRows = count; page.LsList = query.ToList(); page.TotalPages = page.TotalRows / pageSize; if (page.TotalRows % pageSize != 0) page.TotalPages++; } else { var queryable = able.Where(predicate); var count = queryable.Count(); var query = isAsc ? queryable.OrderBy(keySelector).Skip(skip).Take(pageSize) : queryable.OrderByDescending(keySelector).Skip(skip).Take(pageSize); page.TotalRows = count; page.LsList = query.ToList(); page.TotalPages = page.TotalRows / pageSize; if (page.TotalRows % pageSize != 0) page.TotalPages++; } return page; } /// /// 获取实体 /// /// 主键id /// public T GetModelById(object id) { return Entity.Find(id); } /// /// 获取实体(条件) /// /// 条件表达式 /// public T GetModel(Expression bool>> predicate) { return Entity.FirstOrDefault(predicate); } /// /// 查询记录数 /// /// /// public int Count(Expression bool>> predicate) { return predicate != null ? Entity.Where(predicate).Count() : Entity.Count(); } /// /// 是否存在 /// /// /// public bool Exist(Expression bool>> anyLambda) { return Entity.Any(anyLambda); } } }
分页Page类
using System.Collections.Generic; namespace NetCoreWebApi.Repository.Dto { public class Page{ /// /// 当前页 /// public int PageIndex { get; set; } /// /// 总页数 /// public int TotalPages { get; set; } /// /// 集合总数 /// public int TotalRows { get; set; } /// /// 每页项数 /// public int PageSize { get; set; } /// /// 集合 /// public IList LsList { get; set; } } }
二、仓储的泛型的依赖注入。
修改Startup.cs启动类中ConfigureServices方法
public static IContainer ApplicationContainer { get; set; } ////// //负责注入服务 /// /// /// public IServiceProvider ConfigureServices(IServiceCollection services) { //获取数据库连接字符串 var connectionStr = Configuration.GetConnectionString("SqlServer"); services.AddDbContext (options => options.UseSqlServer(connectionStr, e => e.MigrationsAssembly("NetCoreWebApi.Model"))); services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2); //初始化容器 var builder = new ContainerBuilder(); //管道寄居 builder.Populate(services); //注册业务 builder.RegisterAssemblyTypes(Assembly.Load("NetCoreWebApi.Repository"), Assembly.Load("NetCoreWebApi.Repository")) .Where(t => t.Name.EndsWith("Repository")) .AsImplementedInterfaces(); //注册仓储,所有IRepository接口到Repository的映射 builder.RegisterGeneric(typeof(Repository<>)) //InstancePerDependency:默认模式,每次调用,都会重新实例化对象;每次请求都创建一个新的对象; .As(typeof(IRepository<>)).InstancePerDependency(); //构造 ApplicationContainer = builder.Build(); //将AutoFac反馈到管道中 return new AutofacServiceProvider(ApplicationContainer); }
三、测试
修改业务层---UserRepository
给泛型类指定ThUser,红色字体是主要更改部分。
using System.Collections.Generic; using System.Linq; using NetCoreWebApi.Model.Models; using NetCoreWebApi.Repository.Interface; using NetCoreWebApi.Repository.Repository; namespace NetCoreWebApi.Repository.Implement { ////// 业务处理 /// public class UserRepository:IUserRepository { private readonly IRepository _userRepository; /// /// 构造函数 /// /// public UserRepository(IRepository userRepository) { _userRepository = userRepository; } /// /// 添加用户 /// /// /// public int Add(TbUser entity) { return _userRepository.Add(entity); } /// /// 删除用户 /// /// /// public int Remove(TbUser entity) { return _userRepository.Remove(entity); } /// /// 查询用户 /// /// public IList GetAll() { return _userRepository.GetAll().ToList(); } /// /// 条件查询 /// /// 姓名 /// 是否正序 /// 页码 /// 每页大小 /// public object SearchFor(string name, bool isAsc, int pageIndex, int pageSize) { //条件表达式 Expression bool>> predicate = e => string.IsNullOrWhiteSpace(name) || e.UserName.Equals(name); var data = _userRepository.SearchFor(pageIndex, pageSize, predicate, isAsc, e=>e.CreateTime); return data; } } }
多条件查询
稍微修改下条件查询接口
////// 条件查询 /// /// 姓名 /// 姓名1 /// 是否正序 /// 页码 /// 每页大小 /// public object SearchFor(string name, string name1, bool isAsc, int pageIndex, int pageSize) { //条件表达式 Expression bool>> predicate = e => (string.IsNullOrWhiteSpace(name) || e.UserName.Equals(name))&& (string.IsNullOrWhiteSpace(name1)||e.UserName.Equals(name1)); var data = _userRepository.SearchFor(pageIndex, pageSize, predicate, isAsc, e=>e.CreateTime); return data; }
运行项目执行接口,可以看到跟之前一样
如果有其他实体只需要改变传入的T就可以了,不需要再重新创建TEntityRepository