private static Expression BuildExpressionTree(ParameterExpression pe, FilterRule rule, bool useIndexedProperty = false, string indexedPropertyName = null) { if (rule.Rules != null && rule.Rules.Any()) { var expressions = rule.Rules.Select(childRule => BuildExpressionTree(pe, childRule, useIndexedProperty, indexedPropertyName)) .Where(exp => exp != null) .ToList(); var expressionTree = expressions.First(); var counter = 1; while (counter < expressions.Count) { expressionTree = rule.Condition.ToLower() == "or" ? Expression.Or(expressionTree, expressions[counter]) : Expression.And(expressionTree, expressions[counter]); counter++; } return(expressionTree); } if (string.IsNullOrEmpty(rule.Field)) { throw new Exception("属性未设置"); } if (string.IsNullOrEmpty(rule.Operator)) { throw new Exception($"属性【{rule.Field}】运算符未设置"); } Expression propertyExp = null; if (useIndexedProperty) { propertyExp = Expression.Property(pe, indexedPropertyName, Expression.Constant(rule.Field)); } else { // QT 扩展,支持复杂属性 obj.Foo.Boo if (string.IsNullOrEmpty(rule.Table)) { if (pe.Type.GetProperty(rule.Field) == null) { throw new Exception(string.Format("对象【{0}】属性【{1}】不存在", pe.Type.Name, rule.Field)); } propertyExp = Expression.Property(pe, rule.Field); } else { propertyExp = Expression.Property(pe, rule.Table); if (propertyExp.Type.GetProperty(rule.Field) == null) { throw new Exception(string.Format("对象【{0}】属性【{1}】不存在", propertyExp.Type.Name, rule.Field)); } propertyExp = Expression.Property(propertyExp, rule.Field); } } Type type = propertyExp.Type; if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable <>)) { type = type.GetGenericArguments()[0]; } if (!DicTypeOperator.ContainsKey(type.Name) || !DicTypeOperator[type.Name].Contains(rule.Operator.ToLower())) { throw new Exception($"字段【{rule.Field}】不支持运算符【{rule.Operator}】"); } Expression expression; // 检查输入数据的类型是否和字段类型兼容,例如字段类型是数字 try { switch (rule.Operator.ToLower()) { case "in": expression = In(type, rule.Value, propertyExp); break; case "not_in": expression = NotIn(type, rule.Value, propertyExp); break; case "equal": expression = Equals(type, rule.Value, propertyExp); break; case "not_equal": expression = NotEquals(type, rule.Value, propertyExp); break; case "between": expression = Between(type, rule.Value, propertyExp); break; case "not_between": expression = NotBetween(type, rule.Value, propertyExp); break; case "less": expression = LessThan(type, rule.Value, propertyExp); break; case "less_or_equal": expression = LessThanOrEqual(type, rule.Value, propertyExp); break; case "greater": expression = GreaterThan(type, rule.Value, propertyExp); break; case "greater_or_equal": expression = GreaterThanOrEqual(type, rule.Value, propertyExp); break; case "begins_with": expression = BeginsWith(type, rule.Value, propertyExp); break; case "not_begins_with": expression = NotBeginsWith(type, rule.Value, propertyExp); break; case "contains": expression = Contains(type, rule.Value, propertyExp); break; case "not_contains": expression = NotContains(type, rule.Value, propertyExp); break; case "ends_with": expression = EndsWith(type, rule.Value, propertyExp); break; case "not_ends_with": expression = NotEndsWith(type, rule.Value, propertyExp); break; case "is_empty": expression = IsEmpty(propertyExp); break; case "is_not_empty": expression = IsNotEmpty(propertyExp); break; case "is_null": expression = IsNull(propertyExp); break; case "is_not_null": expression = IsNotNull(propertyExp); break; case "mc": // QT扩展运算符:多包含 expression = ContainsAny(type, rule.Value, propertyExp); break; case "sdiff": // QT扩展运算符:几天前,只应用于日期属性 expression = DaysBefore(type, rule.Value, propertyExp); break; case "ediff": // QT扩展运算符:几天后,只应用于日期属性 expression = DaysAfter(type, rule.Value, propertyExp); break; default: throw new Exception($"Unknown expression operator: {rule.Operator}"); } } catch (NotSupportedException) { throw new Exception($"字段【{rule.Field}】输入值【{rule.Value}】不合法"); } return(expression); }
/// <summary> /// Gets the filtered collection after applying the provided filter rules. /// </summary> /// <typeparam name="T">The generic type.</typeparam> /// <param name="queryable">The queryable.</param> /// <param name="filterRule">The filter rule.</param> /// <param name="useIndexedProperty">Whether or not to use indexed property</param> /// <param name="indexedPropertyName">The indexable property to use</param> /// <returns>Filtered IQueryable</returns> public static IQueryable <T> BuildQuery <T>(this IQueryable <T> queryable, FilterRule filterRule, bool useIndexedProperty = false, string indexedPropertyName = null) { string parsedQuery; return(BuildQuery(queryable, filterRule, out parsedQuery, useIndexedProperty, indexedPropertyName)); }