1 /// <summary>
2 /// 实现动态排序
3 /// 来源博客园的一个大神,具体实现原理是利用实体和排序字段自动生成一个表达式
4 /// 再利用IQuerable的方法实现
5 /// 有一部分比较像微软的源码 ZhangQC 2016.10.20
6 /// </summary>
7 public static class DynamicOrder
8 {
9 #region Private 表达式树
10 /// <summary>
11 /// 构建表达式树 结果类似于 j=>j.Name
12 /// </summary>ZhangQc 2016.10.20
13 /// <typeparam name="TEntity"></typeparam>
14 /// <param name="propertyName"></param>
15 /// <param name="resultType"></param>
16 /// <returns></returns>
17 private static LambdaExpression GenerateSelector<TEntity>(String propertyName, out Type resultType) where TEntity : class
18 {
19 PropertyInfo property;
20 Expression propertyAccess;
21 var parameter = Expression.Parameter(typeof(TEntity), "j");
22
23 if (propertyName.Contains('.'))
24 {
25 String[] childProperties = propertyName.Split('.');
26 property = typeof(TEntity).GetProperty(childProperties[0]);
27 propertyAccess = Expression.MakeMemberAccess(parameter, property);
28 for (int i = 1; i < childProperties.Length; i++)
29 {
30 property = property.PropertyType.GetProperty(childProperties[i]);
31 propertyAccess = Expression.MakeMemberAccess(propertyAccess, property);
32 }
33 }
34 else
35 {
36 property = typeof(TEntity).GetProperty(propertyName);
37 propertyAccess = Expression.MakeMemberAccess(parameter, property);
38 }
39
40 resultType = property.PropertyType;
41
42 return Expression.Lambda(propertyAccess, parameter);
43 }
44
45 /// <summary>
46 /// 生成方法调用
47 /// </summary>
48 /// <typeparam name="TEntity"></typeparam>
49 /// <param name="source"></param>
50 /// <param name="methodName"></param>
51 /// <param name="fieldName"></param>
52 /// <returns></returns>
53 private static MethodCallExpression GenerateMethodCall<TEntity>(IQueryable<TEntity> source, string methodName, String fieldName) where TEntity : class
54 {
55 Type type = typeof(TEntity);
56 Type selectorResultType;
57 LambdaExpression selector = GenerateSelector<TEntity>(fieldName, out selectorResultType);
58 MethodCallExpression resultExp = Expression.Call(typeof(Queryable), methodName,
59 new Type[] { type, selectorResultType },
60 source.Expression, Expression.Quote(selector));
61 return resultExp;
62 }
63 #endregion
64
65 public static IOrderedQueryable<TEntity> OrderBy<TEntity>(this IQueryable<TEntity> source, string fieldName) where TEntity : class
66 {
67 MethodCallExpression resultExp = GenerateMethodCall<TEntity>(source, "OrderBy", fieldName);
68 return source.Provider.CreateQuery<TEntity>(resultExp) as IOrderedQueryable<TEntity>;
69 }
70
71 public static IOrderedQueryable<TEntity> OrderByDescending<TEntity>(this IQueryable<TEntity> source, string fieldName) where TEntity : class
72 {
73 MethodCallExpression resultExp = GenerateMethodCall<TEntity>(source, "OrderByDescending", fieldName);
74 return source.Provider.CreateQuery<TEntity>(resultExp) as IOrderedQueryable<TEntity>;
75 }
76
77 public static IOrderedQueryable<TEntity> ThenBy<TEntity>(this IOrderedQueryable<TEntity> source, string fieldName) where TEntity : class
78 {
79 MethodCallExpression resultExp = GenerateMethodCall<TEntity>(source, "ThenBy", fieldName);
80 return source.Provider.CreateQuery<TEntity>(resultExp) as IOrderedQueryable<TEntity>;
81 }
82
83 public static IOrderedQueryable<TEntity> ThenByDescending<TEntity>(this IOrderedQueryable<TEntity> source, string fieldName) where TEntity : class
84 {
85 MethodCallExpression resultExp = GenerateMethodCall<TEntity>(source, "ThenByDescending", fieldName);
86 return source.Provider.CreateQuery<TEntity>(resultExp) as IOrderedQueryable<TEntity>;
87 }
88 public static IOrderedQueryable<TEntity> OrderUsingSortExpression<TEntity>(this IQueryable<TEntity> source, string sortExpression) where TEntity : class
89 {
90 String[] orderFields = sortExpression.Split(',');
91 IOrderedQueryable<TEntity> result = null;
92 for (int currentFieldIndex = 0; currentFieldIndex < orderFields.Length; currentFieldIndex++)
93 {
94 String[] expressionPart = orderFields[currentFieldIndex].Trim().Split(' ');
95 String sortField = expressionPart[0];
96 Boolean sortDescending = (expressionPart.Length == 2) && (expressionPart[1].Equals("DESC", StringComparison.OrdinalIgnoreCase));
97 if (sortDescending)
98 {
99 result = currentFieldIndex == 0 ? source.OrderByDescending(sortField) : result.ThenByDescending(sortField);
100 }
101 else
102 {
103 result = currentFieldIndex == 0 ? source.OrderBy(sortField) : result.ThenBy(sortField);
104 }
105 }
106 return result;
107 }
108
109
110 //使用方法
111 // var query = (from d in ((VinnoTech.Gaia2.DB.g2_dsource[])result)
112 // join p in WebApiApplication.entities.g2_propnames
113 // on d.dsource_item equals p.prop_name
114 // orderby sidx
115 // select new
116 // {
117 // d.dsource_id,
118 // d.dsource_name,
119 // dsource_item = p.prop_description,
120 // d.dsource_description,
121 // dsource_status = d.dsource_status == "1" ? "启用" : "禁用",
122 // d.dsource_expiredday,
123 // dsource_alarmhigh = (d.dsource_alarmhigh == -65535 || d.dsource_alarmhigh == 65535) ? "未禁用" : d.dsource_alarmhigh.ToString(),
124 // dsource_alarmlow = (d.dsource_alarmlow == -65535 || d.dsource_alarmhigh == 65535) ? "未禁用" : d.dsource_alarmhigh.ToString(),
125 // dsource_alarmdeltadata = (d.dsource_alarmdeltadata == -65535 || d.dsource_alarmhigh == 65535) ? "未禁用" : d.dsource_alarmhigh.ToString(),
126 // dsource_alarmidle = (d.dsource_alarmidle == -65535 || d.dsource_alarmhigh == 65535) ? "未禁用" : d.dsource_alarmhigh.ToString(),
127 // d.dsource_formula,
128 // dsource_updatetime = d.dsource_updatetime.ToString("yyyy-MM-dd HH:mm:ss")
129 // }).AsQueryable();
130
131 //page = page <= query.Count() / rows + 1 ? page : 1;
132
133 //query = query.OrderUsingSortExpression("dsource_name asc,dsource_item desc").Skip(rows * (page - 1)).Take(rows);
134 }