程序地带

对于经常接触的分页你确定你真的会吗


对于一直奋斗在crud“前线”的码农, 每天面对的就是形形色色的crud代码,不过写了这么多的crud你确定面对你经常也得topage,getpage确定没什么问题吗?那么今天我就来抛砖一下(目前仅在sqlserver下有效不过目测其他数据库也一样)


大家一般来说都会封装一个分页方法,这是每个开发者都会的技能,对于ef我今天就来讲下正确的分页姿势先上分页代码


一般我们会定义一个分页返回对象当然你也可以用out返回count来实现


/// <summary>
/// 分页集合
/// </summary>
/// <typeparam name="T"></typeparam>
public class PagedResult<T>
{
#region Ctor
/// <summary>
/// 初始化一个新的<c>PagedResult{T}</c>类型的实例。
/// </summary>
/// <param name="total">总记录数。</param>
/// <param name="data">当前页面的数据。</param>
public PagedResult(List<T> data, int total)
{
this.Total = total;
this.Data = data;
}
#endregion
#region Public Properties
/// <summary>
/// 获取或设置总记录数。
/// </summary>
public int Total { get; set; }
/// <summary>
/// 分页数据
/// </summary>
public List<T> Data { get; set; }
#endregion
}

有了这个代码后一般我们会对iqueryable进行封装分页方法,先上一个简单版本


public static async Task<PagedResult<T>> ToPageResultAsync<T>(this IQueryable<T> source, int pageIndex, int pageSize)
{
//设置每次获取多少页
var take = pageSize <= 0 ? 1 : pageSize;
//设置当前页码最小1
var index = pageIndex <= 0 ? 1 : pageIndex;
//需要跳过多少页
var skip = (index - 1) * take;
//获取每次总记录数
var count = await source.CountAsync();
var data = await source.Skip(skip).Take(take).ToListAsync();
return new PagedResult<T>(data, count);
}

这样我们第一个版本的分页代码就封装好了,但是对于这个熟悉的方法很多人会止步于此,毕竟过度优化是很愚蠢的,但是我们会发现一个很重要的优化点是很多人会忽略的就是无意义查询,直接上第二个版本


public static async Task<PagedResult<T>> ToPageResultAsync<T>(this IQueryable<T> source, int pageIndex, int pageSize)
{
//设置每次获取多少页
var take = pageSize <= 0 ? 1 : pageSize;
//设置当前页码最小1
var index = pageIndex <= 0 ? 1 : pageIndex;
//需要跳过多少页
var skip = (index - 1) * take;
//获取每次总记录数
var count = await source.CountAsync();
//当数据库数量小于要跳过的条数就说明没数据直接返回不在查询list
if (count <= skip)
return new PagedResult<T>(new List<T>(0), count);
var data = await source.Skip(skip).Take(take).ToListAsync();
return new PagedResult<T>(data, count);
}

细心的喷友可能发现了仅仅是多了一个判断可以减少跳大页的情况,但是对于这种情况下我们会发现如果在大数据量比如百万往上的情况下往往单个简单的查询会让你感觉性能的低下,明明就查询返回了一条数据怎么要这么久,反而返回多数据的时候变快了,其实这里就有一个问题就是当你


返回的数据库结果仅1条的情况下如果你用了top 2那么他就会一直找count下的数据直到满足2条(个人猜想),所以我们再来优化下分页代码


public static async Task<PagedResult<T>> ToPageResultAsync<T>(this IQueryable<T> source, int pageIndex, int pageSize)
{
//设置每次获取多少页
var take = pageSize <= 0 ? 1 : pageSize;
//设置当前页码最小1
var index = pageIndex <= 0 ? 1 : pageIndex;
//需要跳过多少页
var skip = (index - 1) * take;
//获取每次总记录数
var count = await source.CountAsync();
//当数据库数量小于要跳过的条数就说明没数据直接返回不在查询list
if (count <= skip)
return new PagedResult<T>(new List<T>(0), count);
//获取剩余条数
int remainingCount = count - skip;
//当剩余条数小于take数就取remainingCount
var realTake = remainingCount < take ? remainingCount : take;
var data = await source.Skip(skip).Take(realTake).ToListAsync();
return new PagedResult<T>(data, count);
}

当数据库中剩余的条数减去对应的跳过数目剩余的数目如果不够本次pagesize的时候就不再需要按pagesize获取数据了,所以对于本次查询仅适用realTake就可以了,到此为止分页的正确姿势就展示完了,如果这篇文章对你有帮助就给我点个赞吧谢谢


版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://www.cnblogs.com/xuejiaming/p/14187680.html

随机推荐

JS正则表达式教程(略长)

JS正则表达式教程(略长)

文章提纲:元字符重复限定符分组转义条件或区间零宽断言捕获和非捕获反向引用贪婪和非贪婪反义JS中使用正则1.元字符元字符说明.匹配除换行符以外的任意字符w匹配字母或数字或下划线或汉字s...

呀哈@ 阅读(185)

关系代数运算  概要简记

关系代数运算 概要简记

关系代数中的操作可以分为下面两类:传统的集合运算:并、差、交、笛卡尔积专门的关系运算:投影(对关系进行垂直分割)、选择࿰...

(爱吃鱼的喵) 阅读(468)

低代码,是否能“取代”开发者?

低代码,是否能“取代”开发者?

整理|郑丽媛责编|屠敏头图|CSDN下载自视觉中国在降本增效的趋势下,“低代码”似乎在一夕间变得火热起来。据国际权威分析机构Forrester预测,到2022年࿰...

CSDN资讯 阅读(595)

通过图片触发XssPayload从而绕过WAF

通过图片触发XssPayload从而绕过WAF

XSS设想假设如果XSS的PayLoad被拦截,那么把XSS的PayLoad放到载体里面,这样会不会Bypass呢?一个正常的gif图片加上一个XSS的Pay...

_saulGoodman_ 阅读(216)

自定义一个SpringBoot Starter

自定义一个SpringBoot Starter

文章目录简介使用SpringInitializr创建一个项目定义一个配置信息映射类定义一个Service定义一个配置类自动装配Service在spring.factories中指定自动装配的类安装测试...

chinese_coder 阅读(352)