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 }