为什么要使用泛型仓储?好处是?
前两章在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 IRepository<T> where T : class { /// <summary> /// 添加实体(单个) /// </summary> /// <param name="entity">实体对象</param> int Add(T entity); /// <summary> /// 批量插入实体(多个) /// </summary> /// <param name="list">实体列表</param> int AddRange(List<T> list); /// <summary> /// 删除实体(单个) /// </summary> /// <param name="entity"></param> int Remove(T entity); /// <summary> /// 批量删除实体(多个) /// </summary> /// <param name="list">实体列表</param> int RemoveRange(List<T> list); /// <summary> /// 获取所有 /// </summary> /// <returns></returns> IQueryable<T> GetAll(); /// <summary> /// 分页条件查询 /// </summary> /// <typeparam name="TKey">排序类型</typeparam> /// <param name="pageIndex">当前页</param> /// <param name="pageSize">每页大小</param> /// <param name="predicate">条件表达式</param> /// <param name="isAsc">是否升序排列</param> /// <param name="keySelector">排序表达式</param> /// <returns></returns> Page<T> SearchFor<TKey>(int pageIndex, int pageSize, Expression<Func<T, bool>> predicate, bool isAsc, Expression<Func<T, TKey>> keySelector); /// <summary> /// 获取实体(主键) /// </summary> /// <param name="id">主键id</param> /// <returns></returns> T GetModelById(object id); /// <summary> /// 获取实体(条件) /// </summary> /// <param name="predicate">条件表达式</param> /// <returns></returns> T GetModel(Expression<Func<T, bool>> predicate); /// <summary> /// 查询记录数 /// </summary> /// <param name="predicate">条件表达式</param> /// <returns>记录数</returns> int Count(Expression<Func<T, bool>> predicate); /// <summary> /// 是否存在 /// </summary> /// <param name="anyLambda">查询表达式</param> /// <returns>布尔值</returns> bool Exist(Expression<Func<T, 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<T> : IRepository<T> where T : class { private readonly MyDbContext _dbContext; private DbSet<T> _entity; /// <summary> /// 构造函数 /// </summary> /// <param name="dbContext"></param> public Repository(MyDbContext dbContext) { _dbContext = dbContext; } private DbSet<T> Entity => _entity ?? (_entity = _dbContext.Set<T>()); /// <summary> /// 添加实体(单个) /// </summary> /// <param name="entity">实体对象</param> public int Add(T entity) { Entity.Add(entity); return _dbContext.SaveChanges(); } /// <summary> /// 批量插入实体(多个) /// </summary> /// <param name="list">实体列表</param> public int AddRange(List<T> list) { Entity.AddRange(list); return _dbContext.SaveChanges(); } /// <summary> /// 删除实体(单个) /// </summary> /// <param name="entity"></param> public int Remove(T entity) { Entity.Remove(entity); return _dbContext.SaveChanges(); } /// <summary> /// 批量删除实体(多个) /// </summary> /// <param name="list">实体列表</param> public int RemoveRange(List<T> list) { Entity.RemoveRange(list); return _dbContext.SaveChanges(); } /// <summary> /// 获取所有 /// </summary> /// <returns></returns> public IQueryable<T> GetAll() { return Entity.AsQueryable().AsNoTracking(); } /// <summary> /// 条件查询 /// </summary> /// <typeparam name="TKey">排序类型</typeparam> /// <param name="pageIndex">当前页</param> /// <param name="pageSize">每页大小</param> /// <param name="isAsc">是否升序排列</param> /// <param name="predicate">条件表达式</param> /// <param name="keySelector">排序表达式</param> /// <returns></returns> public Page<T> SearchFor<TKey>(int pageIndex, int pageSize, Expression<Func<T, bool>> predicate, bool isAsc, Expression<Func<T, TKey>> keySelector) { if (pageIndex <= 0 || pageSize <= 0) throw new Exception("pageIndex或pageSize不能小于等于0"); var page = new Page<T> { 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; } /// <summary> /// 获取实体 /// </summary> /// <param name="id">主键id</param> /// <returns></returns> public T GetModelById(object id) { return Entity.Find(id); } /// <summary> /// 获取实体(条件) /// </summary> /// <param name="predicate">条件表达式</param> /// <returns></returns> public T GetModel(Expression<Func<T, bool>> predicate) { return Entity.FirstOrDefault(predicate); } /// <summary> /// 查询记录数 /// </summary> /// <param name="predicate"></param> /// <returns></returns> public int Count(Expression<Func<T, bool>> predicate) { return predicate != null ? Entity.Where(predicate).Count() : Entity.Count(); } /// <summary> /// 是否存在 /// </summary> /// <param name="anyLambda"></param> /// <returns></returns> public bool Exist(Expression<Func<T, bool>> anyLambda) { return Entity.Any(anyLambda); } } }
分页Page类
using System.Collections.Generic; namespace NetCoreWebApi.Repository.Dto { public class Page<T> { /// <summary> /// 当前页 /// </summary> public int PageIndex { get; set; } /// <summary> /// 总页数 /// </summary> public int TotalPages { get; set; } /// <summary> /// 集合总数 /// </summary> public int TotalRows { get; set; } /// <summary> /// 每页项数 /// </summary> public int PageSize { get; set; } /// <summary> /// 集合 /// </summary> public IList<T> LsList { get; set; } } }
二、仓储的泛型的依赖注入。
修改Startup.cs启动类中ConfigureServices方法
public static IContainer ApplicationContainer { get; set; } /// <summary> /// //负责注入服务 /// </summary> /// <param name="services"></param> /// <returns></returns> public IServiceProvider ConfigureServices(IServiceCollection services) { //获取数据库连接字符串 var connectionStr = Configuration.GetConnectionString("SqlServer"); services.AddDbContext<MyDbContext> (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 { /// <summary> /// 业务处理 /// </summary> public class UserRepository:IUserRepository { private readonly IRepository<TbUser> _userRepository; /// <summary> /// 构造函数 /// </summary> /// <param name="userRepository"></param> public UserRepository(IRepository<TbUser> userRepository) { _userRepository = userRepository; } /// <summary> /// 添加用户 /// </summary> /// <param name="entity"></param> /// <returns></returns> public int Add(TbUser entity) { return _userRepository.Add(entity); } /// <summary> /// 删除用户 /// </summary> /// <param name="entity"></param> /// <returns></returns> public int Remove(TbUser entity) { return _userRepository.Remove(entity); } /// <summary> /// 查询用户 /// </summary> /// <returns></returns> public IList<TbUser> GetAll() { return _userRepository.GetAll().ToList(); } /// <summary> /// 条件查询 /// </summary> /// <param name="name">姓名</param> /// <param name="isAsc">是否正序</param> /// <param name="pageIndex">页码</param> /// <param name="pageSize">每页大小</param> /// <returns></returns> public object SearchFor(string name, bool isAsc, int pageIndex, int pageSize) { //条件表达式 Expression<Func<TbUser, bool>> predicate = e => string.IsNullOrWhiteSpace(name) || e.UserName.Equals(name); var data = _userRepository.SearchFor(pageIndex, pageSize, predicate, isAsc, e=>e.CreateTime); return data; } } }
多条件查询
稍微修改下条件查询接口
/// <summary> /// 条件查询 /// </summary> /// <param name="name">姓名</param> /// <param name="name1">姓名1</param> /// <param name="isAsc">是否正序</param> /// <param name="pageIndex">页码</param> /// <param name="pageSize">每页大小</param> /// <returns></returns> public object SearchFor(string name, string name1, bool isAsc, int pageIndex, int pageSize) { //条件表达式 Expression<Func<TbUser, 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