C#表达式目录树系列之3 -- 为EF查询实现动态OrderBy

概要

在后端开发中,我们常碰到这样的需求,用户需要对数据进行排序和分页,但是基于哪个栏位排序不确定,需要根据用户在页面上的操作动态获取,并且可能有一个或多个栏位参与排序。

对于此类需求的一般做法是,前端根据用户的输入生成一个对应的URL,包括分页数据和排序数据。例如: https://xxxx/students?pagestart=1&pagelength=10&orderby=Department desc,Name

对于后端,通过URL地址,获取分页和排序信息,需要使用EF的排序。我们想到的肯定是IQueryable的扩展方法OrderBy,但是OrderBy函数的参数是一个委托,我们并不能直接把解析URL获得的排序栏位的名称传入该方法。需要动态构建该委托。

基于上述需求,显然使用表达式目录树构建排序的表达式时最佳选择。

设计和实现

using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;

    public static class IQueryableExtension {
        public static IQueryable<T> Sorting<T> (this IQueryable<T> source, string sortExpression, string sortDirection = "ASC", bool isThenBy = false) {
            var query = DataSort<T> (source, sortExpression, sortDirection, isThenBy);
            return query;
        }
        private static IQueryable<T> DataSort<T> (IQueryable<T> source, string sortExpression, string sortDirection = "ASC", bool isThenBy = false) {
              string sortingDir = !isThenBy ? "OrderBy" : "ThenBy";
            if (sortDirection.ToUpper ().Trim () == "DESC") {
                sortingDir = !isThenBy ? "OrderByDescending" : "ThenByDescending";
            }
            ParameterExpression oParameter = Expression.Parameter (typeof (T), "o");
            var property = typeof(T).GetProperty (sortExpression);
            var memberExpression = Expression.Property (oParameter, property);
            var orderExpression = Expression.Lambda (memberExpression, new ParameterExpression[] { oParameter });
      		 var resultExpression = Expression.Call(
                typeof(Queryable),
                sortingDir,
                new Type[] {source.ElementType, property.PropertyType},
				new Expression[] { source.Expression,  Expression.Quote(orderExpression)}
            ); 
            return source.Provider.CreateQuery<T>(resultExpression) as IQueryable<T>;    
        }
}
  1. 对于多列排序,第一次要使用OrderBy,后面的排序需要ThenBy, 降序排列同理。
  2. 构建排序的表达式 o=>o.FirstName
  3. 调用排序方法:
    • C# 的Expression.Call有多个重载方法,排序方法称为IQueryable的扩展方法,扩展方法本质上还是静态方法,又要支持泛型。所以选用Call(Type, String, Type[], Expression[])重载方法,即支持泛型有支持静态方法调用。
    • 泛型排序方法有两个泛型类型要指定,一个是泛型的具体类型,第二个是传入列名对应的类型。
    • 在调用扩展方法时候,扩展方法的第一个参数是可省的,相当于哪个对象调用该方法,该对象就对应该参数。但是通过表达式目录树的方式调用该方法,第一个参数是不可以省略的。因此,要指定为source.Expression,source是具体调用该扩展方法的对象,要通过表达式的形式体现,因此为source.Expression。第二个参数是之前第二步构建好的排序表达式。

表达式目录树系列全部文章

  • C#表达式目录树系列之1 – 表达式目录树基本概念
  • C#表达式目录树系列之2 – 常见的表达式目录树的实例
  • C#表达式目录树系列之3 – 为EF查询实现动态OrderBy
  • C#表达式目录树系列之4 – 解决C#泛型约束与无法创建带参数的泛型实例的矛盾
  • C#表达式目录树系列之5 – 动态创建查询表达式

你可能感兴趣的:(.Net,Core,C#基础,c#,后端)