ASP.NET Core 2.2 WebApi 系列【六】泛型仓储模式
为什么要使用泛型仓储?好处是?
前两章在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 <= || pageSize <= ) throw new Exception("pageIndex或pageSize不能小于等于0");
var page = new Page<T> { PageIndex = pageIndex, PageSize = pageSize };
var skip = (pageIndex - ) * 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 != ) 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 != ) 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
ASP.NET Core 2.2 WebApi 系列【六】泛型仓储模式的更多相关文章
- ASP.NET Core 2.2 WebApi 系列【九】使用SignalR (作者:tenghao510 ) 学习及内容补充
原文地址: ASP.NET Core 2.2 WebApi 系列[九]使用SignalR 今天,看到了大牛的这篇博文, 发了一下评论, 我很惊喜, 没想到他很快就回复了我, 而且通过QQ帮助了S ...
- ASP.NET Core 3.0 WebApi 系列【2】.Net Core 3.0+ CodeFirst + MySql 实现数据的迁移
写在前面 在前一小节中,我们创建了基于RESFULL风格的服务.这个小节,尝试使用CodeFirst+MySql 的方式实现数据迁移. 一.开发环境 [1]运行环境:win10 家庭版 [2]开发工具 ...
- ASP.NET Core 3.0 WebApi 系列【1】创建ASP.NET Core WebApi 项目
目录 写在前面 一.运行环境 二.项目搭建 三.测试 API 四.基础知识 五.写在最后 写在前面 C#语言可以创建RESTful服务,被称作WebApi.在这里总结学习使用支持创建.读取.更新.删除 ...
- ASP.NET Core 2.2 WebApi 系列【一】搭建ASP.NET Core WebApi项目
一.步骤 从“文件”菜单中选择“新建”>“项目” . 选择“ASP.NET Core Web 应用程序”模板,再单击“下一步” . 将项目命名为 NetCoreWebApi,然后单击“创建” . ...
- ASP.NET Core 2.2 WebApi 系列【九】使用SignalR
1.添加 SignalR 客户端库 右键点击项目->然后选择“添加” >“客户端库” 提供程序选择:unpkg ,库选择:@aspnet/signalr@1.1.4 选择“选择特定文件” ...
- ASP.NET Core 2.2 WebApi 系列【八】统一返回格式(返回值、模型验证、异常)
现阶段,基本上都是前后端分离项目,这样一来,就需要前后端配合,没有统一返回格式,那么对接起来会很麻烦,浪费时间.我们需要把所有接口及异常错误信息都返回一定的Json格式,有利于前端处理,从而提高了工作 ...
- ASP.NET Core 2.2 WebApi 系列【七】泛型仓储模式和工作单元
在之前的泛型仓储模式实现中,每个增删改都调用了SaveChanges方法,导致每次更新都提交了事务. 在实际开发过程中,我们经常遇到同时操作多张表数据,那么按照之前的写法,对数据库提交了多次操作,开启 ...
- ASP.NET Core 2.2 WebApi 系列【五】MiniProfiler与Swagger集成
MiniProfiler 是一款性能分析的轻量级程序,可以基于action(request)记录每个阶段的耗时时长,还是可以显示访问数据库时的SQL(支持EF.EF Code First)等 一.安装 ...
- ASP.NET Core 2.2 WebApi 系列【四】集成Swagger
Swagger 是一款自动生成在线接口文档+功能测试功能软件 一.安装程序包 通过管理 NuGet 程序包安装,搜索Swashbuckle.AspNetCore 二.配置 Swagger 将 Swag ...
随机推荐
- C#写入(覆盖形式)数据到CSV文件 和 读取CSV文件
/// <summary> /// 写入数据到CSV文件,覆盖形式 /// </summary> /// <param name="csvPath"& ...
- kuangbin专题 数论基础 part1?
线段树专题太难了,那我来做数学吧! 但数学太难了,我......(扯 这两天想了做了查了整理了几道数学. 除了一些进阶的知识,像莫比乌斯反演,杜教筛,min25学不会我跳了,一些基础的思维还是可以记录 ...
- .NET Core的JWT认证的学习
今天学习下JWT,遇到了两个坑爹问题,这里记录下.在 ASP.NET Core 中,授权的设置方式有两种,可以使用角色,也可以使用策略,这里也将简单举例角色.策略的使用. JWT这里不做介绍,如果想了 ...
- JS---动画函数封装:设置任意的一个元素,移动到指定的目标位置
动画函数封装:设置任意的一个元素,移动到指定的目标位置 <!DOCTYPE html> <html lang="en"> <head> < ...
- 二分查找(Java)
题目: 编写程序,完成以下功能: (1)输入5个整数到数组中; (2)使用冒泡法对5个数按从小到大排序,输出排序后的数组; (3)输入一个整数X,在数组中用二分法查找X,找到输出X在数组中的下标,找不 ...
- JavaScript实例:运动的小球
本篇博文通过制作一个小球运动动画的实例,来学习在HTML5的画布上实现动画制作的方法,同时理解面向对象程序设计的基本思想. 1.绘制小球 先在HTML页面中设置一个画布. <canvas id= ...
- js 五种绑定彻底弄懂this,默认绑定、隐式绑定、显式绑定、new绑定、箭头函数绑定详解
壹 ❀ 引 可以说this与闭包.原型链一样,属于JavaScript开发中老生常谈的问题了,百度一搜,this相关的文章铺天盖地.可开发好几年,被几道this题安排明明白白的人应该不在少数(我就是 ...
- Cesium专栏-卫星轨迹
Cesium Cesium 是一款面向三维地球和地图的,世界级的JavaScript开源产品.它提供了基于JavaScript语言的开发包,方便用户快速搭建一款零插件的虚拟地球Web应用,并在性能,精 ...
- A Code Farmer‘s Entertainment
My guitar playing and singing 码农的自娱自乐 https://v.youku.com/v_show/id_XNDM4NTY1MTEwNA==.html?spm=a2hzp ...
- dedecmsV5.7 后台上传m4a的音频之后不展示
问题:dedecmsV5.7 在后台上传了m4a的音频文件(如何添加m4a的音频格式,更改系统-系统基本配置-附件设置)之后,列表里不展示,如图: 解决方案: 打开include/dialog/sel ...