You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

197 lines
8.1KB

  1. using System.Linq.Expressions;
  2. using HealthMonitor.Util.QueryObjects;
  3. namespace HealthMonitor.Core.Query
  4. {
  5. public class QueryExpressionParser<T>
  6. {
  7. private readonly ParameterExpression parameter;
  8. public QueryExpressionParser()
  9. {
  10. parameter = Expression.Parameter(typeof(T));
  11. }
  12. public Expression<Func<T, bool>> ParserConditions(IEnumerable<QueryFilterCondition> conditions)
  13. {
  14. try
  15. {
  16. //将条件转化成表达是的Body
  17. var query = ParseExpressionBody(conditions);
  18. return Expression.Lambda<Func<T, bool>>(query, parameter);
  19. }
  20. catch (Exception)
  21. {
  22. var query = Expression.Constant(false, typeof(bool));
  23. return Expression.Lambda<Func<T, bool>>(query, parameter);
  24. }
  25. }
  26. private Expression ParseExpressionBody(IEnumerable<QueryFilterCondition> conditions)
  27. {
  28. if (conditions == null || conditions.Count() == 0)
  29. {
  30. return Expression.Constant(true, typeof(bool));
  31. }
  32. else if (conditions.Count() == 1)
  33. {
  34. return ParseCondition(conditions.First());
  35. }
  36. else
  37. {
  38. Expression left = ParseCondition(conditions.First());
  39. Expression right = ParseExpressionBody(conditions.Skip(1));
  40. return Expression.AndAlso(left, right);
  41. }
  42. }
  43. private Expression GetValueExpression(QueryFilterCondition condition)
  44. {
  45. string[]? array = null;
  46. switch (condition.Operator)
  47. {
  48. case QueryOperatorEnum.In:
  49. case QueryOperatorEnum.Between:
  50. array = condition.Value!.Split(",".ToCharArray(), StringSplitOptions.RemoveEmptyEntries);
  51. break;
  52. }
  53. switch (condition.ValueType)
  54. {
  55. case QueryValueTypeEnum.Int:
  56. case QueryValueTypeEnum.Long:
  57. {
  58. long data;
  59. if (array != null)
  60. {
  61. return Expression.NewArrayInit(typeof(long), array.Select(e => Expression.Constant(long.TryParse(e, out data) ? data : 0)));
  62. }
  63. return Expression.Constant(long.TryParse(condition.Value, out data) ? data : 0);
  64. }
  65. case QueryValueTypeEnum.Float:
  66. case QueryValueTypeEnum.Double:
  67. case QueryValueTypeEnum.Decimal:
  68. {
  69. double data;
  70. if (array != null)
  71. {
  72. return Expression.NewArrayInit(typeof(double), array.Select(e => Expression.Constant(double.TryParse(e, out data) ? data : 0)));
  73. }
  74. return Expression.Constant(double.TryParse(condition.Value, out data) ? data : 0);
  75. }
  76. case QueryValueTypeEnum.DateTime:
  77. {
  78. DateTime data;
  79. if (array != null)
  80. {
  81. return Expression.NewArrayInit(typeof(DateTime), array.Select(e => Expression.Constant(DateTime.TryParse(e, out data) ? data : DateTime.Now)));
  82. }
  83. return Expression.Constant(DateTime.TryParse(condition.Value, out data) ? data : DateTime.Now);
  84. }
  85. case QueryValueTypeEnum.Boolean:
  86. {
  87. return Expression.Constant(bool.TryParse(condition.Value, out bool data) ? data : false);
  88. }
  89. default:
  90. {
  91. if (array != null)
  92. {
  93. return Expression.NewArrayInit(typeof(string), array.Select(e => Expression.Constant(e)));
  94. }
  95. return Expression.Constant(condition.Value);
  96. }
  97. }
  98. }
  99. private Expression ParseCondition(QueryFilterCondition condition)
  100. {
  101. ParameterExpression p = parameter;
  102. Expression key = Expression.Property(p, condition.Key!);
  103. Expression value = GetValueExpression(condition);
  104. switch (condition.Operator)
  105. {
  106. case QueryOperatorEnum.Contains:
  107. return Expression.Call(key, typeof(string).GetMethod("Contains", new Type[] { typeof(string) })!, value);
  108. case QueryOperatorEnum.Equal:
  109. return Expression.Equal(key, Expression.Convert(value, key.Type));
  110. case QueryOperatorEnum.Greater:
  111. return Expression.GreaterThan(key, Expression.Convert(value, key.Type));
  112. case QueryOperatorEnum.GreaterEqual:
  113. return Expression.GreaterThanOrEqual(key, Expression.Convert(value, key.Type));
  114. case QueryOperatorEnum.Less:
  115. return Expression.LessThan(key, Expression.Convert(value, key.Type));
  116. case QueryOperatorEnum.LessEqual:
  117. return Expression.LessThanOrEqual(key, Expression.Convert(value, key.Type));
  118. case QueryOperatorEnum.NotEqual:
  119. return Expression.NotEqual(key, Expression.Convert(value, key.Type));
  120. case QueryOperatorEnum.In:
  121. return ParaseIn(p, condition, (value as NewArrayExpression)!);
  122. case QueryOperatorEnum.Between:
  123. return ParaseBetween(p, condition);
  124. default:
  125. throw new NotImplementedException("不支持此操作");
  126. }
  127. }
  128. private Expression ParaseBetween(ParameterExpression parameter, QueryFilterCondition conditions)
  129. {
  130. ParameterExpression p = parameter;
  131. Expression key = Expression.Property(p, conditions.Key!);
  132. var valueArr = conditions?.Value?.Split(',');
  133. if (valueArr!.Length != 2)
  134. {
  135. throw new NotImplementedException("ParaseBetween参数错误");
  136. }
  137. double startValue = 0, endValue = 0;
  138. try
  139. {
  140. startValue = double.Parse(valueArr[0]);
  141. endValue = double.Parse(valueArr[1]);
  142. }
  143. catch
  144. {
  145. throw new NotImplementedException("ParaseBetween参数只能为数字");
  146. }
  147. if (startValue >= endValue) throw new ArgumentOutOfRangeException("ParaseBetween参数起始值和终止值错误");
  148. Expression expression = Expression.Constant(true, typeof(bool));
  149. //开始位置
  150. Expression startvalue = Expression.Constant(startValue);
  151. Expression start = Expression.GreaterThanOrEqual(key, Expression.Convert(startvalue, key.Type));
  152. Expression endvalue = Expression.Constant(endValue);
  153. Expression end = Expression.LessThanOrEqual(key, Expression.Convert(endvalue, key.Type));
  154. return Expression.AndAlso(start, end);
  155. }
  156. private Expression ParaseIn(ParameterExpression parameter, QueryFilterCondition conditions, NewArrayExpression values)
  157. {
  158. ParameterExpression p = parameter;
  159. Expression key = Expression.Property(p, conditions.Key!);
  160. Expression expression = Expression.Constant(false, typeof(bool));
  161. foreach (var value in values.Expressions)
  162. {
  163. Expression right = Expression.Equal(key, Expression.Convert(value, key.Type));
  164. expression = Expression.Or(expression, right);
  165. }
  166. //var valueArr = conditions.Value.Split(',');
  167. //foreach (var itemVal in valueArr)
  168. //{
  169. // Expression value = Expression.Constant(itemVal);
  170. // Expression right = Expression.Equal(key, Expression.Convert(value, key.Type));
  171. // expression = Expression.Or(expression, right);
  172. //}
  173. return expression;
  174. }
  175. }
  176. }