LambdaExpressionBuilder.cs 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Linq.Expressions;
  5. using System.Reflection;
  6. namespace YBEE.EQM.Core
  7. {
  8. /// <summary>
  9. /// 动态生成查询表达式
  10. /// </summary>
  11. public static class LambdaExpressionBuilder
  12. {
  13. private static Expression GetExpression(ParameterExpression parameter, Condition condition)
  14. {
  15. var propertyParam = Expression.Property(parameter, condition.Field);
  16. var propertyInfo = propertyParam.Member as PropertyInfo;
  17. if (propertyInfo == null)
  18. throw new MissingMemberException(nameof(Condition), condition.Field);
  19. //Support Nullable<>
  20. var realPropertyType = Nullable.GetUnderlyingType(propertyInfo.PropertyType) ?? propertyInfo.PropertyType;
  21. if (propertyInfo.PropertyType.IsGenericType &&
  22. propertyInfo.PropertyType.GetGenericTypeDefinition() == typeof(Nullable<>))
  23. propertyParam = Expression.Property(propertyParam, "Value");
  24. //Support IEnumerable && IEnumerable<T>
  25. if (condition.Op != QueryTypeEnum.StdIn && condition.Op != QueryTypeEnum.StdNotIn)
  26. {
  27. condition.Value = Convert.ChangeType(condition.Value, realPropertyType);
  28. }
  29. else
  30. {
  31. var typeOfValue = condition.Value.GetType();
  32. var typeOfList = typeof(IEnumerable<>).MakeGenericType(realPropertyType);
  33. if (typeOfValue.IsGenericType && typeOfList.IsAssignableFrom(typeOfValue))
  34. condition.Value = typeof(Enumerable)
  35. .GetMethod("ToArray", BindingFlags.Public | BindingFlags.Static)
  36. ?.MakeGenericMethod(realPropertyType)
  37. .Invoke(null, new[] { condition.Value });
  38. }
  39. var constantParam = Expression.Constant(condition.Value);
  40. switch (condition.Op)
  41. {
  42. case QueryTypeEnum.Equals:
  43. return Expression.Equal(propertyParam, constantParam);
  44. case QueryTypeEnum.NotEquals:
  45. return Expression.NotEqual(propertyParam, constantParam);
  46. case QueryTypeEnum.Contains:
  47. return Expression.Call(propertyParam, "Contains", null, constantParam);
  48. case QueryTypeEnum.NotContains:
  49. return Expression.Not(Expression.Call(propertyParam, "Contains", null, constantParam));
  50. case QueryTypeEnum.StartsWith:
  51. return Expression.Call(propertyParam, "StartsWith", null, constantParam);
  52. case QueryTypeEnum.EndsWith:
  53. return Expression.Call(propertyParam, "EndsWith", null, constantParam);
  54. case QueryTypeEnum.GreaterThan:
  55. return Expression.GreaterThan(propertyParam, constantParam);
  56. case QueryTypeEnum.GreaterThanOrEquals:
  57. return Expression.GreaterThanOrEqual(propertyParam, constantParam);
  58. case QueryTypeEnum.LessThan:
  59. return Expression.LessThan(propertyParam, constantParam);
  60. case QueryTypeEnum.LessThanOrEquals:
  61. return Expression.LessThanOrEqual(propertyParam, constantParam);
  62. case QueryTypeEnum.StdIn:
  63. return Expression.Call(typeof(Enumerable), "Contains", new[] { realPropertyType }, constantParam, propertyParam);
  64. case QueryTypeEnum.StdNotIn:
  65. return Expression.Not(Expression.Call(typeof(Enumerable), "Contains", new[] { realPropertyType }, constantParam, propertyParam));
  66. default:
  67. break;
  68. }
  69. return null;
  70. }
  71. private static Expression GetGroupExpression(ParameterExpression parameter, List<Condition> orConditions)
  72. {
  73. if (orConditions.Count == 0)
  74. return null;
  75. var exps = orConditions.Select(c => GetExpression(parameter, c)).ToList();
  76. return exps.Aggregate<Expression, Expression>(null, (left, right) =>
  77. left == null ? right : Expression.OrElse(left, right));
  78. }
  79. public static Expression<Func<T, bool>> BuildLambda<T>(IEnumerable<Condition> conditions)
  80. {
  81. if (conditions == null || !conditions.Any())
  82. return x => true;
  83. var parameter = Expression.Parameter(typeof(T), "x");
  84. //简单条件
  85. var simpleExps = conditions
  86. .ToList()
  87. .FindAll(c => string.IsNullOrEmpty(c.OrGroup))
  88. .Select(c => GetExpression(parameter, c))
  89. .ToList();
  90. //复杂条件
  91. var complexExps = conditions
  92. .ToList()
  93. .FindAll(c => !string.IsNullOrEmpty(c.OrGroup))
  94. .GroupBy(x => x.OrGroup)
  95. .Select(g => GetGroupExpression(parameter, g.ToList()))
  96. .ToList();
  97. var exp = simpleExps.Concat(complexExps).Aggregate<Expression, Expression>(null, (left, right) =>
  98. left == null ? right : Expression.AndAlso(left, right));
  99. return Expression.Lambda<Func<T, bool>>(exp, parameter);
  100. }
  101. public static Expression<Func<T, bool>> BuildAndAlsoLambda<T>(IEnumerable<Condition> conditions)
  102. {
  103. if (conditions == null || !conditions.Any())
  104. return x => true;
  105. var parameter = Expression.Parameter(typeof(T), "x");
  106. var simpleExps = conditions
  107. .ToList()
  108. .Select(c => GetExpression(parameter, c))
  109. .ToList();
  110. var exp = simpleExps.Aggregate<Expression, Expression>(null, (left, right) =>
  111. left == null ? right : Expression.AndAlso(left, right));
  112. return Expression.Lambda<Func<T, bool>>(exp, parameter);
  113. }
  114. public static Expression<Func<T, bool>> BuildOrElseLambda<T>(IEnumerable<Condition> conditions)
  115. {
  116. if (conditions == null || !conditions.Any())
  117. return x => true;
  118. var parameter = Expression.Parameter(typeof(T), "x");
  119. var simpleExps = conditions
  120. .ToList()
  121. .Select(c => GetExpression(parameter, c))
  122. .ToList();
  123. var exp = simpleExps.Aggregate<Expression, Expression>(null, (left, right) =>
  124. left == null ? right : Expression.OrElse(left, right));
  125. return Expression.Lambda<Func<T, bool>>(exp, parameter);
  126. }
  127. }
  128. /// <summary>
  129. /// 查询条件
  130. /// </summary>
  131. [Serializable]
  132. public class Condition
  133. {
  134. /// <summary>
  135. /// 字段名
  136. /// </summary>
  137. public string Field { get; set; }
  138. /// <summary>
  139. /// 操作符
  140. /// </summary>
  141. public QueryTypeEnum Op { get; set; }
  142. /// <summary>
  143. /// 字段值
  144. /// </summary>
  145. public object Value { get; set; }
  146. /// <summary>
  147. /// 分组名称
  148. /// </summary>
  149. public string OrGroup { get; set; }
  150. }
  151. }