ABP中GetAll查询出来的IQueryable类型数据,扩展进行排序

基于IEnumerable<T>接口的LINQ to Object扩展函数运行开发人员提供Func<T, TResult>类型的委托实现排序,看一个简单的例子:
public class Person
{
  public Person() : this(Guid.NewGuid().ToString("N"), DateTime.Now) { }

  
public Person(String name, DateTime birth)   {     this.Name = name;     this.Birth = birth;   }   
  public
String Name { get; set; }   public DateTime Birth { get; set; } } IEnumerable<Person> persons = new Person[] { new Person(), new Person(), new Person() }; IOrderedEnumerable<Person> persons2 = persons.OrderBy(p => p.Name); IOrderedEnumerable<Person> persons3 = persons.OrderBy(delegate(Person p) { return p.Name; }); IOrderedEnumerable<Person> persons4 = persons.OrderBy(p => p.Name, StringComparer.CurrentCultureIgnoreCase);
上面类型中的属性是已知并且可被推导的,如果属性只有一个名称怎么才能够依然可以排序呢?比如下面的写法:
IOrderedEnumerable<Person> persons = persons.OrderBy("Name");
 
IQueryable<T>接口可以将查询解析为表达式树,我们可以看到IQueryable<T>的OrderBy、OrderByDescending扩展函数分别相比IEnumerable<T>多了两个接受Expression<Func<T, TResult>>的函数:
public static IOrderedQueryable<TSource> OrderBy<TSource, TKey>(this IQueryable<TSource> source, Expression<Func<TSource, TKey>> keySelector);
public static IOrderedQueryable<TSource> OrderBy<TSource, TKey>(this IQueryable<TSource> source, Expression<Func<TSource, TKey>> keySelector, IComparer<TKey> comparer);
public static IOrderedQueryable<TSource> OrderByDescending<TSource, TKey>(this IQueryable<TSource> source, Expression<Func<TSource, TKey>> keySelector);
public static IOrderedQueryable<TSource> OrderByDescending<TSource, TKey>(this IQueryable<TSource> source, Expression<Func<TSource, TKey>> keySelector, IComparer<TKey> comparer);

 

也就说我们可以动态构建Lambda表达式来实现动态调用OrderBy、OrderByDescending函数。看一个例子:
1 Type type = typeof(T);
2 ParameterExpression arg = Expression.Parameter(type, "p");
3 PropertyInfo property = type.GetProperty(propertyName);
4 Expression expr = Expression.Property(arg, property);
5 Type delegateType = typeof(Func<,>).MakeGenericType(typeof(T), property.PropertyType);
6 LambdaExpression lambda = Expression.Lambda(delegateType, expr, arg);

 

arg就是传递的参数类型,也就是Func<T, TResult>的T类型。通过Expression.Property创建了函数执行体,并定义访问传递参数的某一个属性。最后创建出表达式,等同于p => p.属性。最后找到Queryable静态类型中定义的OrderBy、OrderByDescending函数动态调用就可以实现传递属性名称实现排序。
 1 /// <summary>
 2 /// 排序的扩展类
 3 /// </summary>
 4 public static class QueryableOrderEx
 5 {
 6 
 7     /// <summary>
 8     /// 顺序排序
 9     /// </summary>
10     /// <typeparam name="T"></typeparam>
11     /// <param name="source"></param>
12     /// <param name="propertyName"></param>
13     /// <returns></returns>
14     public static IOrderedQueryable<T> OrderBy<T>(this IQueryable<T> source, String propertyName)
15     {
16         return InternalOrder<T>(source, propertyName, "OrderBy");
17     }
18 
19 
20     /// <summary>
21     /// 倒序排序
22     /// </summary>
23     /// <typeparam name="T"></typeparam>
24     /// <param name="source"></param>
25     /// <param name="propertyName"></param>
26     /// <returns></returns>
27     public static IOrderedQueryable<T> OrderByDescending<T>(this IQueryable<T> source, String propertyName)
28     {
29         return InternalOrder<T>(source, propertyName, "OrderByDescending");
30     }
31 
32 
33     /// <summary>
34     /// 
35     /// </summary>
36     /// <typeparam name="T"></typeparam>
37     /// <param name="source"></param>
38     /// <param name="propertyName"></param>
39     /// <returns></returns>
40     public static IOrderedQueryable<T> ThenBy<T>(this IOrderedQueryable<T> source, String propertyName)
41     {
42         return InternalOrder<T>(source, propertyName, "ThenBy");
43     }
44 
45     /// <summary>
46     /// 
47     /// </summary>
48     /// <typeparam name="T"></typeparam>
49     /// <param name="source"></param>
50     /// <param name="propertyName"></param>
51     /// <returns></returns>
52     public static IOrderedQueryable<T> ThenByDescending<T>(this IOrderedQueryable<T> source, String propertyName)
53     {
54         return InternalOrder<T>(source, propertyName, "ThenByDescending");
55     }
56 
57 
58     /// <summary>
59     /// 
60     /// </summary>
61     /// <typeparam name="T"></typeparam>
62     /// <param name="source"></param>
63     /// <param name="propertyName"></param>
64     /// <param name="methodName"></param>
65     /// <returns></returns>
66     private static IOrderedQueryable<T> InternalOrder<T>(IQueryable<T> source, String propertyName, String methodName)
67     {
68         Type type = typeof(T);
69         ParameterExpression arg = Expression.Parameter(type, "p");
70         PropertyInfo property = type.GetProperty(propertyName);
71         Expression expr = Expression.Property(arg, property);
72         Type delegateType = typeof(Func<,>).MakeGenericType(typeof(T), property.PropertyType);
73         LambdaExpression lambda = Expression.Lambda(delegateType, expr, arg);
74 
75         return ((IOrderedQueryable<T>)(typeof(Queryable).GetMethods().Single(
76             p => String.Equals(p.Name, methodName, StringComparison.Ordinal)
77                 && p.IsGenericMethodDefinition
78                 && p.GetGenericArguments().Length == 2
79                 && p.GetParameters().Length == 2)
80             .MakeGenericMethod(typeof(T), property.PropertyType)
81             .Invoke(null, new Object[] { source, lambda })));
82     }
83 }
1 IEnumerable<Person> persons = new Person[] { new Person(), new Person(), new Person() };
2 IOrderedQueryable<Person> persons2 = persons.AsQueryable().OrderBy("Name");
3 IOrderedQueryable<Person> persons3 = persons.AsQueryable().OrderByDescending("Name");

 

1 //ABP项目中的使用例子,参考STK项目
 query = !string.IsNullOrEmpty(input.Sorting) 2 ? query = (input.SortBy == SortByEnum.ASC ? QueryableOrderEx.OrderBy<STKForm.STKFormHead>(query, input.Sorting) : QueryableOrderEx.OrderByDescending<STKForm.STKFormHead>(query, input.Sorting)) 3 : query.OrderByDescending(t => t.CreationTime);

 

 

 

 

posted @ 2021-09-26 20:55  殇琉璃  阅读(484)  评论(0编辑  收藏  举报