C#中Lambda表达式树Expression实现多过滤条件多排序

 1.编写参数类SearchCondition可以传入多个过滤条件和多个排序条件

 

2.编写方法ConvertToLamdaExpression实现将多个查询条件

复制代码
    //
    // 摘要:
    //     查询条件转Lamda表达式
    //
    // 类型参数:
    //   T:
    //     数据类型
    //
    // 返回结果:
    //     表达式
    public Expression<Func<T, bool>> ConvertToLamdaExpression<T>()
    {
        Expression<Func<T, bool>> expression = PredicateExtension.True<T>();
        foreach (SearchItem searchItem in SearchItems)
        {
            string field = searchItem.Field;
            SearchMethod searchMethod = searchItem.SearchMethod;
            DataType dataType = searchItem.DataType;
            object value = searchItem.Value;
            if (string.IsNullOrEmpty(field) || value == null)
            {
                continue;
            }

            Expression expression2 = null;
            ParameterExpression parameterExpression = Expression.Parameter(typeof(T), "p");
            Expression expression3 = Expression.PropertyOrField(parameterExpression, field);
            Expression expression4 = Expression.Constant(value);
            if (expression4.Type.Equals(typeof(JsonElement)))
            {
                expression4 = Expression.Constant(value.ToString());
            }

            Guid result3;
            if (expression3.Type.Equals(typeof(OperationType)))
            {
                expression4 = Expression.Constant((OperationType)int.Parse(value.ToString()), typeof(OperationType));
            }
            else if (expression3.Type.Equals(typeof(DateTime)) && searchMethod != SearchMethod.BetweenAnd)
            {
                expression4 = Expression.Constant(DateTime.Parse(value.ToString()), typeof(DateTime));
            }
            else if (expression3.Type.Equals(typeof(DateTime?)) && searchMethod != SearchMethod.BetweenAnd)
            {
                expression4 = Expression.Constant(DateTime.Parse(value.ToString()), typeof(DateTime?));
            }
            else if (expression3.Type.Equals(typeof(Guid)))
            {
                if (Guid.TryParse(value.ToString(), out var _))
                {
                    expression4 = Expression.Constant(Guid.Parse(value.ToString()), typeof(Guid));
                }
            }
            else if (!expression3.Type.Equals(typeof(Guid?)))
            {
                expression4 = (expression3.Type.Equals(typeof(float)) ? Expression.Constant(float.Parse(value.ToString()), typeof(float)) : (expression3.Type.Equals(typeof(float?)) ? Expression.Constant(float.Parse(value.ToString()), typeof(float?)) : (expression3.Type.Equals(typeof(double)) ? Expression.Constant(double.Parse(value.ToString()), typeof(double)) : (expression3.Type.Equals(typeof(double?)) ? Expression.Constant(double.Parse(value.ToString()), typeof(double?)) : (expression3.Type.Equals(typeof(int)) ? Expression.Constant(int.Parse(value.ToString()), typeof(int)) : (expression3.Type.Equals(typeof(int?)) ? Expression.Constant(int.Parse(value.ToString()), typeof(int?)) : (expression3.Type.Equals(typeof(bool)) ? Expression.Constant(bool.Parse(value.ToString()), typeof(bool)) : (expression3.Type.Equals(typeof(bool?)) ? Expression.Constant(bool.Parse(value.ToString()), typeof(bool?)) : ((!expression3.Type.IsEnum) ? Expression.Constant(value.ToString(), typeof(string)) : ((!Enum.TryParse(expression3.Type, value.ToString(), out object result2)) ? Expression.Constant(value.ToString(), typeof(string)) : Expression.Constant(result2, expression3.Type)))))))))));
            }
            else if (Guid.TryParse(value.ToString(), out result3))
            {
                expression4 = Expression.Constant(Guid.Parse(value.ToString()), typeof(Guid?));
            }

            switch (searchMethod)
            {
                case SearchMethod.Equal:
                    expression2 = Expression.Equal(expression3, expression4);
                    break;
                case SearchMethod.LessThan:
                    expression2 = Expression.LessThan(expression3, expression4);
                    break;
                case SearchMethod.LessThanOrEqual:
                    expression2 = Expression.LessThanOrEqual(expression3, expression4);
                    break;
                case SearchMethod.GreaterThan:
                    expression2 = Expression.GreaterThan(expression3, expression4);
                    break;
                case SearchMethod.GreaterThanOrEqual:
                    expression2 = Expression.GreaterThanOrEqual(expression3, expression4);
                    break;
                case SearchMethod.BetweenAnd:
                    {
                        string[] array = value.ToString().Split(',');
                        ConstantExpression right = ((dataType == DataType.DateTime) ? Expression.Constant(Convert.ToDateTime(array[0]), typeof(DateTime)) : Expression.Constant(array[0], typeof(string)));
                        ConstantExpression right2 = ((dataType == DataType.DateTime) ? Expression.Constant(Convert.ToDateTime(array[1]), typeof(DateTime)) : Expression.Constant(array[1], typeof(string)));
                        expression2 = Expression.GreaterThanOrEqual(expression3, right);
                        Expression<Func<T, bool>> second = Expression.Lambda<Func<T, bool>>(expression2, new ParameterExpression[1] { parameterExpression });
                        expression = expression.And(second);
                        expression2 = Expression.LessThanOrEqual(expression3, right2);
                        second = Expression.Lambda<Func<T, bool>>(expression2, new ParameterExpression[1] { parameterExpression });
                        expression = expression.And(second);
                        expression2 = null;
                        break;
                    }
                case SearchMethod.Like:
                    {
                        MethodInfo method5 = ((dataType == DataType.Int) ? typeof(List<int>).GetMethod("Contains", new Type[1] { typeof(List<int>) }) : typeof(string).GetMethod("Contains", new Type[1] { typeof(string) }));
                        expression2 = Expression.Call(expression3, method5, expression4);
                        break;
                    }
                case SearchMethod.RightLike:
                    {
                        MethodInfo method2 = ((dataType == DataType.Int) ? typeof(List<int>).GetMethod("Contains", new Type[1] { typeof(List<int>) }) : typeof(string).GetMethod("EndsWith", new Type[1] { typeof(string) }));
                        expression2 = Expression.Call(expression3, method2, expression4);
                        break;
                    }
                case SearchMethod.LeftLike:
                    {
                        MethodInfo method6 = ((dataType == DataType.Int) ? typeof(List<int>).GetMethod("Contains", new Type[1] { typeof(List<int>) }) : typeof(string).GetMethod("StartsWith", new Type[1] { typeof(string) }));
                        expression2 = Expression.Call(expression3, method6, expression4);
                        break;
                    }
                case SearchMethod.Include:
                    {
                        MethodInfo method4 = typeof(Enumerable).GetMethods().First((MethodInfo m) => m.Name == "Contains" && m.GetParameters().Length == 2).MakeGenericMethod(typeof(string));
                        ConstantExpression arg = Expression.Constant(value.ToString().Split(",").ToList(), typeof(IEnumerable<string>));
                        Expression arg2 = Expression.Call(expression3, expression3.Type.GetMethod("ToString", Type.EmptyTypes));
                        expression2 = Expression.Call(method4, arg, arg2);
                        break;
                    }
                case SearchMethod.NotInclude:
                    {
                        MethodInfo method3 = typeof(Enumerable).GetMethods().First((MethodInfo m) => m.Name == "Contains" && m.GetParameters().Length == 2).MakeGenericMethod(typeof(string));
                        Expression.Constant(value.ToString().Split(",").ToList(), typeof(IEnumerable<string>));
                        Expression expression5 = Expression.Call(expression3, expression3.Type.GetMethod("ToString", Type.EmptyTypes));
                        expression2 = Expression.Not(Expression.Call(method3, expression5, expression5));
                        break;
                    }
                case SearchMethod.OrLike:
                    {
                        MethodInfo method = ((dataType == DataType.Int) ? typeof(List<int>).GetMethod("Contains", new Type[1] { typeof(List<int>) }) : typeof(string).GetMethod("Contains", new Type[1] { typeof(string) }));
                        expression2 = Expression.Call(expression3, method, expression4);
                        Expression<Func<T, bool>> second = Expression.Lambda<Func<T, bool>>(expression2, new ParameterExpression[1] { parameterExpression });
                        expression = expression.Or(second);
                        expression2 = null;
                        break;
                    }
                case SearchMethod.NotEqual:
                    expression2 = Expression.NotEqual(expression3, expression4);
                    break;
            }

            if (expression2 != null)
            {
                Expression<Func<T, bool>> second2 = Expression.Lambda<Func<T, bool>>(expression2, new ParameterExpression[1] { parameterExpression });
                expression = expression.And(second2);
            }
        }

        return expression;
    }

    public Expression<Func<List<T>, bool>> BuildContainsExpression<T>(T value)
    {
        ParameterExpression parameterExpression = Expression.Parameter(typeof(List<T>), "list");
        ConstantExpression constantExpression = Expression.Constant(value, typeof(T));
        return Expression.Lambda<Func<List<T>, bool>>(Expression.Call(parameterExpression, "Contains", null, constantExpression), new ParameterExpression[1] { parameterExpression });
    }
复制代码

 

3.条件过滤调用时需使用Compile方法将类型转换一下,否则提示如下错误

           #region 条件过滤
           searchCondition.AddDefaultSearchItem(false);
           var where = searchCondition.ConvertToLamdaExpression<WorkStationInfo>();
           allWorkStations = allWorkStations.Where(where.Compile());
           #endregion

 

4.编写方法ConvertToOrderLamdaExpression将多个查询条件转换为lambda

复制代码
    public List<Tuple<Expression<Func<T, object>>, OrderByType>> ConvertToOrderLamdaExpression<T>()
    {
        List<Tuple<Expression<Func<T, object>>, OrderByType>> list = new List<Tuple<Expression<Func<T, object>>, OrderByType>>();
        List<SortItem> sortItem = SortItem;
        if (sortItem != null && sortItem.Count > 0)
        {
            foreach (SortItem item2 in SortItem)
            {
                ParameterExpression parameterExpression = Expression.Parameter(typeof(T), "p");
                string name = CultureInfo.CurrentCulture.TextInfo.ToTitleCase(item2.Field.ToLower()).First().ToString()
                    .ToUpper() + item2.Field.Substring(1);
                Expression<Func<T, object>> item = Expression.Lambda<Func<T, object>>(Expression.Convert(Expression.Property(parameterExpression, typeof(T).GetProperty(name)), typeof(object)), new ParameterExpression[1] { parameterExpression });
                list.Add(Tuple.Create(item, item2.OrderType));
            }
        }

        return list;
    }
复制代码

 

5.排序调用

复制代码
#region 排序
var order = searchCondition.ConvertToOrderLamdaExpression<WorkStationInfo>();
int index = 0;
order.ForEach(item =>
{
    if (item.Item2 == OrderByType.Asc)
    {
        if (index == 0)
        {
            allWorkStations = allWorkStations.OrderBy(item.Item1.Compile());
        }
        else
        {
            allWorkStations = (allWorkStations as IOrderedEnumerable<WorkStationInfo>).ThenBy(item.Item1.Compile());
        }
    }
    else
    {
        if (index == 0)
        {
            allWorkStations = allWorkStations.OrderByDescending(item.Item1.Compile());
        }
        else
        {
            allWorkStations = (allWorkStations as IOrderedEnumerable<WorkStationInfo>).ThenByDescending(item.Item1.Compile());
        }
    }

    index++;
});
#endregion
复制代码
ThenBy在实际使用中必须使用链式编程的方法写在orderby后边,所以通过将类型转换为IOrderedEnumerable<>后在thenby实现与orderby分开排序。

 

 

2025-05-23 11:30:00【出处】:https://www.cnblogs.com/jiangyuhu/p/18892730

=======================================================================================

posted on 2025-05-23 11:31  jack_Meng  阅读(21)  评论(0)    收藏  举报

导航