一、前言

前面我们知道了表达树的基本知识,也明白了怎么遍历和修改一个表达式,这里我们就一个实际的场景来进行功能开发。

表达式系列目录

C# 表达式树讲解(一) <https://www.cnblogs.com/snailblog/p/11521043.html>

C# 表达式树遍历(二) <https://www.cnblogs.com/snailblog/p/11521335.html>

C# 表达式树分页扩展(三)

C# 表达式树Lambda扩展(四) <https://www.cnblogs.com/snailblog/p/11525118.html>

二、分页扩展


在实际的开发中,肯定会遇到这样的应用场景,一个数据源需要在页面上进行分页显示,并且页面上需要对该数据源有一个排名。本来分页可以在数据库层面完成,但是因为这里有一个排名功能,所谓的排名,就是需要查询出所有满足条件的数据,然后按照某个算法升序或者降序排列,然后按照进行排名。排名之后,然后根据分页信息,将当前页的数据返回给页面,当然中间还有自定义排序的因素。

怎么取数据源和怎么排序,这里先不做介绍,我们就实现对一个数据源分页的功能。

我们先定义好分页的实体对象

分页请求对象PageRequest.cs,因为在【ORM之Dapper运用
<https://www.cnblogs.com/snailblog/p/11516315.html>】已经说明,所以这里我就只粘贴处代码
public class PageRequest { /// <summary> /// 每页条数 /// </summary> public int
PageSize {get; set; } /// <summary> /// 当前页数 /// </summary> public int
PageIndex {get; set; } /// <summary> /// 排序字段 /// </summary> public string
SortBy {get; set; } /// <summary> /// 排序方式(desc、asc) /// </summary> public
string Direction { get; set; } /// <summary> /// 获取排序sql语句 /// </summary> ///
<returns></returns> public string GetOrderBySql() { if (string
.IsNullOrWhiteSpace(SortBy)) {return ""; } var resultSql = new StringBuilder("
ORDER BY"); string dir = Direction; if (string.IsNullOrWhiteSpace(dir)) { dir =
"ASC"; } if (SortBy.Contains("&")) { resultSql.Append("").Append(string.Join(",
", SortBy.Split('&').Select(e => $" {e} {dir}").ToArray())); } else {
resultSql.Append(SortBy).Append("").Append(dir);//默认处理方式 } return
resultSql.ToString(); } } View Code
分页的返回对象PageResponse.cs
/// <summary> /// 通用分页返回 /// </summary> /// <typeparam name="T"></typeparam>
public class PageResponse<T> { /// <summary> /// 总条数 /// </summary> public long
TotalCount {get; set; } /// <summary> /// 返回 /// </summary> public List<T>
Items {get; set; } /// <summary> /// 当前页 /// </summary> public long PageIndex {
get; set; } /// <summary> /// 每页条数 /// </summary> public long PageSize { get;
set; } /// <summary> /// 总页数 /// </summary> public long TotalPages { get; set; }
/// <summary> /// 返回筛选集合 /// </summary> public Dictionary<string, List<string>>
ResultFilter =new Dictionary<string, List<string>>(); } View Code
对数据集分页方法的实现
public class PFTPage { /// <summary> /// 对数据集分页 /// </summary> /// <typeparam
name="T">数据集对象</typeparam> /// <param name="source">数据集</param> /// <param
name="page">分页信息</param> /// <returns></returns> public static PageResponse<T>
DataPagination<T>(IQueryable<T> source, PageRequest page) where T :class, new()
{ var sesultData =new PageResponse<T>(); bool isAsc = page.Direction.ToLower()
== "asc" ? true : false; string[] _order = page.SortBy.Split('&');
MethodCallExpression resultExp =null; foreach (string item in _order) { string
_orderPart = item; _orderPart = Regex.Replace(_orderPart, @"\s+", ""); string[]
_orderArry = _orderPart.Split(' ');string _orderField = _orderArry[0]; bool
sort = isAsc;if (_orderArry.Length == 2) { isAsc = _orderArry[1].ToUpper() == "
ASC" ? true : false; } var parameter = Expression.Parameter(typeof(T), "t");
var property =typeof(T).GetProperty(_orderField); var propertyAccess =
Expression.MakeMemberAccess(parameter, property); var orderByExp =
Expression.Lambda(propertyAccess, parameter); resultExp = Expression.Call(typeof
(Queryable), isAsc ? "OrderBy" : "OrderByDescending", new Type[] { typeof(T),
property.PropertyType }, source.Expression, Expression.Quote(orderByExp)); }
var tempData = source.Provider.CreateQuery<T>(resultExp); sesultData.PageIndex
= page.PageIndex; sesultData.PageSize = page.PageSize; sesultData.TotalCount =
tempData.Count(); sesultData.TotalPages = sesultData.TotalCount /
sesultData.PageSize;if (sesultData.TotalCount % sesultData.PageSize > 0) {
sesultData.TotalPages += 1; } sesultData.Items = tempData.Skip(page.PageSize *
(page.PageIndex - 1)).Take(page.PageSize).ToList();return sesultData; } }
 

为了测试,我们定义一个学生课程成绩的测试类
public class ScoreClass { public string CourseName { get; set; } public string
StudentName {get; set; } public decimal Score { get; set; } }
调用代码
var datas = new List<ScoreClass>(); datas.Add(new ScoreClass { CourseName = "数学
", StudentName = "学生A", Score = 60 }); datas.Add(new ScoreClass { CourseName = "
数学", StudentName = "学生B", Score = 65 }); datas.Add(new ScoreClass { CourseName
= "数学", StudentName = "学生C", Score = 70 }); datas.Add(new ScoreClass {
CourseName = "数学", StudentName = "学生D", Score = 75 }); datas.Add(new ScoreClass
{ CourseName = "数学", StudentName = "学生E", Score = 80 }); datas.Add(new
ScoreClass { CourseName = "数学", StudentName = "学生F", Score = 81 }); datas.Add(
new ScoreClass { CourseName = "数学", StudentName = "学生G", Score = 82 });
datas.Add(new ScoreClass { CourseName = "数学", StudentName = "学生H", Score = 83
}); datas.Add(new ScoreClass { CourseName = "数学", StudentName = "学生I", Score =
84 });//按照Score降序排序取第一个(5条数据) var page = new PageRequest() { Direction= "desc",
PageIndex=1, PageSize=5, SortBy= "Score" }; var result =
PFTPage.DataPagination(datas.AsQueryable(), page); Console.WriteLine($"
分页结果:\n{string.Join("\n", result.Items.Select(e=>$"{e.StudentName}
{e.CourseName} {e.Score}"))}");
运行结果


<https://img2018.cnblogs.com/blog/1764554/201909/1764554-20190915111644677-47682316.png>

监控一下result


<https://img2018.cnblogs.com/blog/1764554/201909/1764554-20190915111645486-1833326556.png>

返回的都是我们希望返回的数据。

分页公共方法里面,就是根据PageRequest里面的内容,动态的生成表达式树的查询,然后在对数据集使用我们生成的查询表达式树,就返回我们想到的数据集。

三、总结

实现数据分页的公共方法,在后面的遇到数据分页的时候,就会显得非常的方便。有没有感觉很好玩,那么下一篇我们在利用这些知识对Lambda表达式进行扩展。