一、前言

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

表达式系列目录

C# 表达式树讲解(一)

C# 表达式树遍历(二)

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

C# 表达式树Lambda扩展(四)

二、分页扩展

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

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

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

分页请求对象PageRequest.cs,因为在【ORM之Dapper运用】已经说明,所以这里我就只粘贴处代码

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();
}
}

分页的返回对象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>>(); }

对数据集分页方法的实现

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}"))}");

运行结果

监控一下result

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

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

三、总结

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

C# 表达式树分页扩展(三)的更多相关文章

  1. C# 表达式树Lambda扩展(四)

    一.前言 本来计算这篇文章在后面需要运用的时候写的,但是既然写到表达式的扩展呢,就一起写完吧. 看到这个标题就有一种疑问,Lambda表达式本来就是表达式树,还需要怎么扩展?那就看看下面的内容,你就知 ...

  2. C# 表达式树讲解(一)

    一.前言 一直想写一篇Dpper的定制化扩展的文章,但是里面会设计到对Lambda表达式的解析,而解析Lambda表达式,就必须要知道表达式树的相关知识点.我希望能通过对各个模块的知识点或者运用能够多 ...

  3. C# 表达式树遍历(二)

    一.前言 上一篇我们对表达式树有了初步的认识,这里我们将对表达式树进行遍历,只有弄清楚了他的运行原理,我们才可以对他进行定制化修改. 表达式系列目录 C# 表达式树讲解(一) C# 表达式树遍历(二) ...

  4. C#复习笔记(4)--C#3:革新写代码的方式(Lambda表达式和表达式树)

    Lambda表达式和表达式树 先放一张委托转换的进化图 看一看到lambda简化了委托的使用. lambda可以隐式的转换成委托或者表达式树.转换成委托的话如下面的代码: Func<string ...

  5. C#编程(六十六)----------表达式树总结

    表达式树总结 基础 表达式树提供了一个将可执行代码转换成数据的方法.如果你要在执行代码之前修改或转换此代码,那么它是很有用的.有其是当你要将C#代码----如LINQ查询表达式转换成其他代码在另一个程 ...

  6. C#高级编程六十六天----表达式树总结【转】

    https://blog.csdn.net/shanyongxu/article/details/47257139 表达式树总结 基础 表达式树提供了一个将可执行代码转换成数据的方法.如果你要在执行代 ...

  7. Lind.DDD.ExpressionExtensions动态构建表达式树,实现对数据集的权限控制

    回到目录 Lind.DDD框架里提出了对数据集的控制,某些权限的用户为某些表添加某些数据集的权限,具体实现是在一张表中存储用户ID,表名,检索字段,检索值和检索操作符,然后用户登陆后,通过自己权限来构 ...

  8. LinQ实战学习笔记(三) 序列,查询操作符,查询表达式,表达式树

    序列 延迟查询执行 查询操作符 查询表达式 表达式树 (一) 序列 先上一段代码, 这段代码使用扩展方法实现下面的要求: 取进程列表,进行过滤(取大于10M的进程) 列表进行排序(按内存占用) 只保留 ...

  9. C#3.0新特性:隐式类型、扩展方法、自动实现属性,对象/集合初始值设定、匿名类型、Lambda,Linq,表达式树、可选参数与命名参数

    一.隐式类型var 从 Visual C# 3.0 开始,在方法范围中声明的变量可以具有隐式类型var.隐式类型可以替代任何类型,编译器自动推断类型. 1.var类型的局部变量必须赋予初始值,包括匿名 ...

随机推荐

  1. Unity的赛车游戏实现思路

    unity目前版本实现赛车的技术方案主要有3种: 1.wheelCollider,设置motorTorque.brakeTorque.steerAngle来实现车子的推动和转弯,优点是上手简单,而且很 ...

  2. 转载 | CSS实现单行、多行文本溢出显示省略号(…)

    本文引自:https://www.cnblogs.com/wyaocn/p/5830364.html 首先,要知道css的三条属性. overflow:hidden; //超出的文本隐藏 text-o ...

  3. golang 结合实例更好的理解参数传递和指针

    关于参数传递 其实go的参数传递,核心就是一句话:go里所有参数传递都是值传递,既把参数复制一份放到函数里去用. go的函数传参,不管参数是什么类型,都会复制一份,然后新的参数在函数内部被使用. 不像 ...

  4. (2019版本可用)【idea的安装,激活,设置,卸载】

    前言 也差不多也可以使用简单快捷的idea软件了,相对于elicpse而言的话,idea是非常好用的,虽然现在涉及不是很广. 什么是idea? IDEA 全称IntelliJ IDEA,是用于java ...

  5. final,权限,引用类型数据

    1. final关键字 1.概述 为了避免子类出现随意改写父类的情况,java提供了关键字final,用于修饰不可改变内容 final:不可改变,可以修饰类,方法和变量 类:被修饰的类,不能用于继承 ...

  6. 《深入理解Java虚拟机》- Java虚拟机是如何加载Java类的?

    Java虚拟机是如何加载Java类的?  这个问题也就是面试常问到的Java类加载机制.在年初面试百战之后,菜鸟喜鹊也是能把这流程倒背如流啊!但是,也只是字面上的背诵,根本就是像上学时背书考试一样. ...

  7. Tomcat中文乱码问题

    新从官网下载的Tomcat7和Tomcat8,在运行的时候都会有乱码的问题,就此发现问题,我们就给它就地正法! 经过初步的分析,问题产生的大概原因是由于Tomcat的log日志模块不识别中文的问题, ...

  8. 【Python3爬虫】学习分布式爬虫第一步--Redis分布式爬虫初体验

    一.写在前面 之前写的爬虫都是单机爬虫,还没有尝试过分布式爬虫,这次就是一个分布式爬虫的初体验.所谓分布式爬虫,就是要用多台电脑同时爬取数据,相比于单机爬虫,分布式爬虫的爬取速度更快,也能更好地应对I ...

  9. Jvm内存泄漏

    内存泄漏和内存溢出的关系 内存泄露:指程序中动态分配内存给一些临时对象,但是对象不会被GC所回收,它始终占用内存.即被分配的对象可达但已无用. 内存溢出:指程序运行过程中无法申请到足够的内存而导致的一 ...

  10. 企查查app新增企业数据抓取

    企查查每日新增企业数据抓取尚未完成的工作: 需要自行抓包获取设备id,appid,sign等等 sign和时间戳保持一致即可 把所有的数据库.redis配置 无法自动登录,账号需要独立 redis数据 ...