表达式树在LINQ动态查询

时间:2024-09-21 11:05:56

动态构建表达式树,最佳实践版,很实用!

  1. public class FilterCollection : Collection<IList<Filter>>
  2. {
  3. public FilterCollection()
  4. : base()
  5. { }
  6. }
  7. public class Filter
  8. {
  9. public string PropertyName { get; set; }
  10. public Op Operation { get; set; }
  11. public object Value { get; set; }
  12. }
  13. public enum Op
  14. {
  15. Equals,
  16. GreaterThan,
  17. LessThan,
  18. GreaterThanOrEqual,
  19. LessThanOrEqual,
  20. Contains,
  21. StartsWith,
  22. EndsWith
  23. }

通过上面的类可以动态构建复杂的查询条件,下面具体调用的类哦

  1. using Infrastructure.Model;
  2. using System;
  3. using System.Collections.Generic;
  4. using System.Linq;
  5. using System.Linq.Expressions;
  6. using System.Reflection;
  7. using System.Text;
  8. using System.Threading.Tasks;
  9. namespace Infrastructure.Operation
  10. {
  11. public static class LambdaExpressionBuilder
  12. {
  13. private static MethodInfo containsMethod = typeof(string).GetMethod("Contains");
  14. private static MethodInfo startsWithMethod =
  15. typeof(string).GetMethod("StartsWith", new Type[] { typeof(string) });
  16. private static MethodInfo endsWithMethod =
  17. typeof(string).GetMethod("EndsWith", new Type[] { typeof(string) });
  18. private static Expression GetExpression(ParameterExpression param, Filter filter)
  19. {
  20. MemberExpression member = Expression.Property(param, filter.PropertyName);
  21. Expression handledMember = member;
  22. ConstantExpression constant = Expression.Constant(filter.Value);
  23. if (member.Member.MemberType == MemberTypes.Property)
  24. {
  25. Type propertyType = ((PropertyInfo)member.Member).PropertyType;
  26. if (propertyType == typeof(string))
  27. {
  28. handledMember = Expression.Call(member, typeof(string).GetMethod("ToLower", System.Type.EmptyTypes));
  29. }
  30. if (propertyType == typeof(DateTime?))
  31. {
  32. handledMember = Expression.Property(member, typeof(DateTime?).GetProperty("Value"));
  33. }
  34. }
  35. switch (filter.Operation)
  36. {
  37. case Op.Equals:
  38. return Expression.Equal(handledMember, constant);
  39. case Op.GreaterThan:
  40. return Expression.GreaterThan(handledMember, constant);
  41. case Op.GreaterThanOrEqual:
  42. return Expression.GreaterThanOrEqual(handledMember, constant);
  43. case Op.LessThan:
  44. return Expression.LessThan(handledMember, constant);
  45. case Op.LessThanOrEqual:
  46. return Expression.LessThanOrEqual(handledMember, constant);
  47. case Op.Contains:
  48. return Expression.Call(handledMember, containsMethod, constant);
  49. case Op.StartsWith:
  50. return Expression.Call(handledMember, startsWithMethod, constant);
  51. case Op.EndsWith:
  52. return Expression.Call(handledMember, endsWithMethod, constant);
  53. }
  54. return null;
  55. }
  56. private static BinaryExpression GetORExpression(ParameterExpression param, Filter filter1, Filter filter2)
  57. {
  58. Expression bin1 = GetExpression(param, filter1);
  59. Expression bin2 = GetExpression(param, filter2);
  60. return Expression.Or(bin1, bin2);
  61. }
  62. private static Expression GetExpression(ParameterExpression param, IList<Filter> orFilters)
  63. {
  64. if (orFilters.Count == 0)
  65. return null;
  66. Expression exp = null;
  67. if (orFilters.Count == 1)
  68. {
  69. exp = GetExpression(param, orFilters[0]);
  70. }
  71. else if (orFilters.Count == 2)
  72. {
  73. exp = GetORExpression(param, orFilters[0], orFilters[1]);
  74. }
  75. else
  76. {
  77. while (orFilters.Count > 0)
  78. {
  79. var f1 = orFilters[0];
  80. var f2 = orFilters[1];
  81. if (exp == null)
  82. {
  83. exp = GetORExpression(param, orFilters[0], orFilters[1]);
  84. }
  85. else
  86. {
  87. exp = Expression.Or(exp, GetORExpression(param, orFilters[0], orFilters[1]));
  88. }
  89. orFilters.Remove(f1);
  90. orFilters.Remove(f2);
  91. if (orFilters.Count == 1)
  92. {
  93. exp = Expression.Or(exp, GetExpression(param, orFilters[0]));
  94. orFilters.RemoveAt(0);
  95. }
  96. }
  97. }
  98. return exp;
  99. }
  100. public static Expression<Func<T, bool>> GetExpression<T>(FilterCollection filters)
  101. {
  102. if (filters == null || filters.Count == 0)
  103. return null;
  104. ParameterExpression param = Expression.Parameter(typeof(T), "t");
  105. Expression exp = null;
  106. if (filters.Count == 1)
  107. {
  108. exp = GetExpression(param, filters[0]);
  109. }
  110. else if (filters.Count == 2)
  111. {
  112. exp = Expression.AndAlso(GetExpression(param, filters[0]), GetExpression(param, filters[1]));
  113. }
  114. else
  115. {
  116. while (filters.Count > 0)
  117. {
  118. var f1 = filters[0];
  119. var f2 = filters[1];
  120. var f1Andf2 = Expression.AndAlso(GetExpression(param, filters[0]), GetExpression(param, filters[1]));
  121. if (exp == null)
  122. {
  123. exp = f1Andf2;
  124. }
  125. else
  126. {
  127. exp = Expression.AndAlso(exp, f1Andf2);
  128. }
  129. filters.Remove(f1);
  130. filters.Remove(f2);
  131. if (filters.Count == 1)
  132. {
  133. exp = Expression.AndAlso(exp, GetExpression(param, filters[0]));
  134. filters.RemoveAt(0);
  135. }
  136. }
  137. }
  138. return Expression.Lambda<Func<T, bool>>(exp, param);
  139. }
  140. }
  141. }

再来一个OrderBy动态构建

  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Linq.Expressions;
  5. using System.Reflection;
  6. using System.Text;
  7. namespace Jurassic.Sooil.Com
  8. {
  9. public static class OrderExpression
  10. {
  11. public static IOrderedQueryable<T> OrderBy<T>(this IQueryable<T> source, string property)
  12. {
  13. return ApplyOrder<T>(source, property, "OrderBy");
  14. }
  15. public static IOrderedQueryable<T> OrderByDescending<T>(this IQueryable<T> source, string property)
  16. {
  17. return ApplyOrder<T>(source, property, "OrderByDescending");
  18. }
  19. public static IOrderedQueryable<T> ThenBy<T>(this IOrderedQueryable<T> source, string property)
  20. {
  21. return ApplyOrder<T>(source, property, "ThenBy");
  22. }
  23. public static IOrderedQueryable<T> ThenByDescending<T>(this IOrderedQueryable<T> source, string property)
  24. {
  25. return ApplyOrder<T>(source, property, "ThenByDescending");
  26. }
  27. static IOrderedQueryable<T> ApplyOrder<T>(IQueryable<T> source, string property, string methodName)
  28. {
  29. string[] props = property.Split('.');
  30. Type type = typeof(T);
  31. ParameterExpression arg = Expression.Parameter(type, "x");
  32. Expression expr = arg;
  33. foreach (string prop in props)
  34. {
  35. // use reflection (not ComponentModel) to mirror LINQ
  36. PropertyInfo pi = type.GetProperty(prop);
  37. expr = Expression.Property(expr, pi);
  38. type = pi.PropertyType;
  39. }
  40. Type delegateType = typeof(Func<,>).MakeGenericType(typeof(T), type);
  41. LambdaExpression lambda = Expression.Lambda(delegateType, expr, arg);
  42. object result = typeof(Queryable).GetMethods().Single(
  43. method => method.Name == methodName
  44. && method.IsGenericMethodDefinition
  45. && method.GetGenericArguments().Length == 2
  46. && method.GetParameters().Length == 2)
  47. .MakeGenericMethod(typeof(T), type)
  48. .Invoke(null, new object[] { source, lambda });
  49. return (IOrderedQueryable<T>)result;
  50. }
  51. }
  52. }

至此动态构建LINQ查询结束!花了上班时间一上午,还是相当值得的,不过被项目经理知道了得哭死!

不管如何,学到手的才是自己的!

相关文章