C# linq动态查询

本文记录一下 动态生成linq查询条件


实现代码

var filterList = LinqFilterHelper.GetFilterList<Model>(searchModel);
var lambda = LinqFilterHelper.CombineExpressions(filterList.ToArray());
var list = list.Where(lambda.Compile()).ToList();

相关帮助类 LinqFilterHelper

/// <summary>
/// 
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="searchModel"></param>
/// <returns></returns>
public static List<Expression<Func<T, Boolean>>> GetFilterList<T>(object searchModel)
{
    try
    {
        var dynamicSearchModel = JsonHelper.JsonToObject<Models.Models.DynamicSearchModel>(JsonHelper.ObjectToJson(searchModel));
        if (dynamicSearchModel == null || dynamicSearchModel.ConditionList == null)
            return null;

        // 创建参数表达式
        // 创建一个表示类型T的参数表达式,名称为"x"。
        ParameterExpression param = Expression.Parameter(typeof(T), "x");
        var list = new List<Expression<Func<T, Boolean>>>();
        var props = typeof(T).GetProperties(BindingFlags.Public | BindingFlags.IgnoreCase | BindingFlags.Instance);
        foreach (var fieldCondition in dynamicSearchModel.ConditionList)
        {
            Expression<Func<T, Boolean>> combinedCondition = null;
            // 临时存储or条件
            var tempOrFilterList = new List<Expression<Func<T, Boolean>>>();
            foreach (var condition in fieldCondition.Conditions)
            {
                var fieldFilter = GetFieldFilter<T>(props, param, fieldCondition.Field, condition.Type, condition.FirstValue, condition.SecondValue);
                if (fieldFilter != null)
                {
                    tempOrFilterList.Add(fieldFilter);
                }
            }
            if (tempOrFilterList.Count > 0)
            {
                if (combinedCondition == null)
                {
                    combinedCondition = tempOrFilterList[0];
                }
                if (tempOrFilterList.Count > 1)
                {
                    for (int i = 1; i < tempOrFilterList.Count; i++)
                    {
                        var orElse = Expression.OrElse(combinedCondition.Body, tempOrFilterList[i].Body);
                        combinedCondition = Expression.Lambda<Func<T, Boolean>>(orElse, combinedCondition.Parameters[0]);
                    }
                }
                else
                {
                    combinedCondition = tempOrFilterList[0];
                }
                list.Add(combinedCondition);
            }
        }
        return list;
    }
    catch (Exception ex)
    {
        return null;
    }
}


/// <summary>
/// 生成具体查询语句
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="param">参数表达式</param>
/// <param name="fieldName">字段名</param>
/// <param name="logicType">查询类型  eq/in/between</param>
/// <param name="firstValue">查询值</param>
/// <param name="secondValue">查询次值</param>
/// <returns></returns>
private static Expression<Func<T, bool>> GetFieldFilter<T>(PropertyInfo[] props, ParameterExpression param, string fieldName, string logicType, object firstValue, object secondValue)
{
    var prop = props.FirstOrDefault(p => p.Name.ToLower() == fieldName.ToLower());
    Expression<Func<T, bool>> condition = null;
    if (prop != null)
    {
        // 创建一个表示属性或字段访问的  属性表达式, 将参数param和过滤条件的键(filter.Key)关联起来
        MemberExpression member = Expression.PropertyOrField(param, fieldName);
        // 创建一个包含过滤条件值的      常量表达式
        ConstantExpression constant = Expression.Constant(firstValue);
        
        switch (logicType.ToLower())
        {
            case "eq":
                MethodInfo equalsMethod = typeof(string).GetMethod("Equals", new[] { typeof(string), typeof(StringComparison) });
                MethodCallExpression equalsCall = Expression.Call(member, equalsMethod, constant, Expression.Constant(StringComparison.OrdinalIgnoreCase));
                // 创建 Lambda 表达式
                condition = Expression.Lambda<Func<T, bool>>(equalsCall, param);
                break;
            case "in":
                // 创建一个包含过滤条件值的      常量表达式
                constant = Expression.Constant(JsonHelper.JsonToObject<List<string>>(JsonHelper.ObjectToJson(firstValue)).Select(s => s.ToLowerInvariant()));
                // 创建将属性转换为小写的表达式
                MethodInfo toLowerMethod = typeof(string).GetMethod("ToLowerInvariant", Type.EmptyTypes);
                MethodCallExpression toLowerCall = Expression.Call(member, toLowerMethod);

                // 获取 Contains 方法的 MethodInfo,并泛型化为 string 类型
                MethodInfo containsMethod = typeof(Enumerable)
                      .GetMethods(BindingFlags.Public | BindingFlags.Static)
                      .First(m => m.Name == "Contains" && m.GetParameters().Length == 2)
                      .MakeGenericMethod(typeof(string)); // 泛型化为集合元素类型

                // 构建 MethodCallExpression,调用 Enumerable.Contains 方法,传入集合和属性 表示 collection.Contains(property.ToLower())
                MethodCallExpression containsCall = Expression.Call(
                    containsMethod,
                    constant,
                    toLowerCall
                );
                // 创建 Lambda 表达式
                condition = Expression.Lambda<Func<T, bool>>(containsCall, param);
                break;
            case "lt":
                if (prop.PropertyType.Name.ToLower() == "string")
                {
                    // 创建将属性转换为小写的表达式
                    MethodInfo toLowerMethod1 = typeof(string).GetMethod("ToLowerInvariant", Type.EmptyTypes);
                    MethodCallExpression toLowerMember = Expression.Call(member, toLowerMethod1!);
                    MethodCallExpression toLowerConstant = Expression.Call(constant, toLowerMethod1!);

                    // 创建string.Compare方法调用表达式
                    MethodInfo compareMethodInfo = typeof(string).GetMethod("Compare", new[] { typeof(string), typeof(string), typeof(StringComparison) });
                    Expression comparison = Expression.Call(compareMethodInfo, toLowerMember, toLowerConstant, Expression.Constant(StringComparison.Ordinal));

                    // 创建比较表达式(GreaterThanOrEqual)
                    Expression lessThan = Expression.LessThan(comparison, Expression.Constant(0));

                    condition = Expression.Lambda<Func<T, bool>>(lessThan, param);
                }
                else
                {
                    // 创建大于等于表达式
                    BinaryExpression body = Expression.LessThan(param, constant);
                    // 创建lambda表达式
                    condition = Expression.Lambda<Func<T, bool>>(body, param);
                }
                break;
            case "lte":
                if (prop.PropertyType.Name.ToLower() == "string")
                {
                    // 创建将属性转换为小写的表达式
                    MethodInfo toLowerMethod1 = typeof(string).GetMethod("ToLowerInvariant", Type.EmptyTypes);
                    MethodCallExpression toLowerMember = Expression.Call(member, toLowerMethod1!);
                    MethodCallExpression toLowerConstant = Expression.Call(constant, toLowerMethod1!);

                    // 创建string.Compare方法调用表达式
                    MethodInfo compareMethodInfo = typeof(string).GetMethod("Compare", new[] { typeof(string), typeof(string), typeof(StringComparison) });
                    Expression comparison = Expression.Call(compareMethodInfo, toLowerMember, toLowerConstant, Expression.Constant(StringComparison.Ordinal));

                    // 创建比较表达式(GreaterThanOrEqual)
                    Expression lessThanOrEqual = Expression.LessThanOrEqual(comparison, Expression.Constant(0));

                    condition = Expression.Lambda<Func<T, bool>>(lessThanOrEqual, param);
                }
                else
                {
                    // 创建大于等于表达式
                    BinaryExpression body = Expression.LessThanOrEqual(param, constant);
                    // 创建lambda表达式
                    condition = Expression.Lambda<Func<T, bool>>(body, param);
                }
                break;
            case "gt":
                if (prop.PropertyType.Name.ToLower() == "string")
                {
                    // 创建将属性转换为小写的表达式
                    MethodInfo toLowerMethod1 = typeof(string).GetMethod("ToLowerInvariant", Type.EmptyTypes);
                    MethodCallExpression toLowerMember = Expression.Call(member, toLowerMethod1!);
                    MethodCallExpression toLowerConstant = Expression.Call(constant, toLowerMethod1!);

                    // 创建string.Compare方法调用表达式
                    MethodInfo compareMethodInfo = typeof(string).GetMethod("Compare", new[] { typeof(string), typeof(string), typeof(StringComparison) });
                    Expression comparison = Expression.Call(compareMethodInfo, toLowerMember, toLowerConstant, Expression.Constant(StringComparison.Ordinal));

                    // 创建比较表达式
                    Expression greaterThan = Expression.GreaterThan(comparison, Expression.Constant(0));

                    condition = Expression.Lambda<Func<T, bool>>(greaterThan, param);
                }
                else
                {
                    // 创建大于等于表达式
                    BinaryExpression body = Expression.GreaterThan(param, constant);
                    // 创建lambda表达式
                    condition = Expression.Lambda<Func<T, bool>>(body, param);
                }
                break;
            case "gte": //大于等于
                if (prop.PropertyType.Name.ToLower() == "string")
                {
                    // 创建将属性转换为小写的表达式
                    MethodInfo toLowerMethod1 = typeof(string).GetMethod("ToLowerInvariant", Type.EmptyTypes);
                    MethodCallExpression toLowerMember = Expression.Call(member, toLowerMethod1!);
                    MethodCallExpression toLowerConstant = Expression.Call(constant, toLowerMethod1!);

                    // 创建string.Compare方法调用表达式
                    MethodInfo compareMethodInfo = typeof(string).GetMethod("Compare", new[] { typeof(string), typeof(string), typeof(StringComparison) });
                    Expression comparison = Expression.Call(compareMethodInfo, toLowerMember, toLowerConstant, Expression.Constant(StringComparison.Ordinal));

                    // 创建比较表达式
                    Expression greaterThanOrEqual = Expression.GreaterThanOrEqual(comparison, Expression.Constant(0));

                    condition = Expression.Lambda<Func<T, bool>>(greaterThanOrEqual, param);
                }
                else
                {
                    // 创建大于等于表达式
                    BinaryExpression body = Expression.GreaterThanOrEqual(param, constant);
                    // 创建lambda表达式
                    condition = Expression.Lambda<Func<T, bool>>(body, param);
                }
                break;
            case "between":
                // 创建一个包含过滤条件值的      常量表达式
                ConstantExpression secondConstant = Expression.Constant(secondValue);
                if (prop.PropertyType.Name.ToLower() == "string")
                {
                    // 创建将属性转换为小写的表达式
                    MethodInfo toLowerMethod1 = typeof(string).GetMethod("ToLowerInvariant", Type.EmptyTypes);
                    // 创建ToLowerInvariant方法调用表达式(对于member、constant和secondConstant)
                    MethodCallExpression toLowerMember = Expression.Call(member, toLowerMethod1!);
                    MethodCallExpression toLowerConstant = Expression.Call(constant, toLowerMethod1!);
                    MethodCallExpression toLowerSecondConstant = Expression.Call(secondConstant, toLowerMethod1!);

                    // 创建string.Compare方法调用表达式
                    MethodInfo compareMethodInfo = typeof(string).GetMethod("Compare", new[] { typeof(string), typeof(string), typeof(StringComparison) });
                    Expression greaterComparison = Expression.Call(compareMethodInfo, toLowerMember, toLowerConstant, Expression.Constant(StringComparison.Ordinal));
                    // 创建 大于等于 比较表达式
                    Expression greaterThanOrEqual = Expression.GreaterThanOrEqual(greaterComparison, Expression.Constant(0));

                    Expression lessComparison = Expression.Call(compareMethodInfo, toLowerMember, toLowerSecondConstant, Expression.Constant(StringComparison.Ordinal));
                    // 创建 小于等于 比较表达式
                    Expression lessThanOrEqual = Expression.LessThanOrEqual(lessComparison, Expression.Constant(0));
                    
                    // 组合两个比较表达式为逻辑与(AndAlso)
                    BinaryExpression andExpression = Expression.AndAlso(greaterThanOrEqual, lessThanOrEqual);
                    condition = Expression.Lambda<Func<T, bool>>(andExpression, param);
                } 
                else
                {
                    // 创建大于等于表达式
                    BinaryExpression greaterThanOrEqual = Expression.GreaterThanOrEqual(param, constant);
                    BinaryExpression lessThanOrEqual = Expression.LessThanOrEqual(param, secondConstant);
                    // 组合两个比较表达式为逻辑与(AndAlso)
                    BinaryExpression andExpression = Expression.AndAlso(greaterThanOrEqual, lessThanOrEqual);

                    // 创建lambda表达式
                    condition = Expression.Lambda<Func<T, bool>>(andExpression, param);
                }
                break;
            default:
                condition = null;
                break;
        }
    }
    return condition;
}

/// <summary>
/// 条件汇总
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="expressions"></param>
/// <returns></returns>
/// <exception cref="ArgumentException"></exception>
public static Expression<Func<T, bool>> CombineExpressions<T>(params Expression<Func<T, bool>>[] expressions)
{
    if (expressions == null || expressions.Length == 0)
    {
        throw new ArgumentException("No expressions provided.");
    }

    // 第一个表达式作为起点
    Expression<Func<T, bool>> combined = expressions[0];

    // 逐个拼接剩余的表达式
    for (int i = 1; i < expressions.Length; i++)
            {
                // 创建 AndAlso 表达式
                var andAlso = Expression.AndAlso(combined.Body, expressions[i].Body);

                // 使用 LambdaExpression.Update 方法来更新参数和主体
                combined = Expression.Lambda<Func<T, bool>>(andAlso, combined.Parameters[0]);
            }

    return combined;
}

相关实体类

/// <summary>
/// 动态查询类
/// </summary>
public class DynamicSearchModel
{
    /// <summary>
    /// 排序
    /// </summary>
    public List<SortModel> SortList { get; set; }

    /// <summary>
    /// 
    /// </summary>
    public List<TableHeaderModel> TableHead { get; set; }
    /// <summary>
    /// 描述 : 查询条件列表 当条件列表为空或不填时,则不设查询条件
    /// 空值 : False
    /// 默认 : 
    /// </summary>
    public List<ConditionFieldModel> ConditionList { get; set; }

}

/// <summary>
/// 字段条件
/// </summary>
public class ConditionFieldModel
{
    /// <summary>
    /// 描述 : 字段
    /// 空值 : False
    /// 默认 : 
    /// </summary>
    public string Field { get; set; }

    /// <summary>
    /// 描述 : 条件
    /// 空值 : False
    /// 默认 : 
    /// </summary>
    public List<ConditionModel> Conditions { get; set; }
}

/// <summary>
/// 条件
/// </summary>
public class ConditionModel
{
    /// <summary>
    /// 描述 : 条件类型 eq:等于,ne:不等于,lt:小于,lte:小于等于,gt:大于,gte:大于等于,like:模糊匹配,in:包含, notin:不包含,between:在...之间
    /// 空值 : False
    /// 默认 : 
    /// </summary>
    public string Type { get; set; }

    /// <summary>
    /// 描述 : 该参数可为任意值,当类型为boolean时,只可以使用eq类型。当类型为in时,需传输Array对象
    /// 空值 : False
    /// 默认 : 
    /// </summary>
    public object FirstValue { get; set; }

    /// <summary>
    /// 描述 : 该参数只在类型为between时使用,为between的第二个值
    /// 空值 : False
    /// 默认 : 
    /// </summary>
    public object SecondValue { get; set; }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值