You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Entity Framework仓储模式:同一属性多值时动态Where改OR实现

问题描述

基于Entity Framework的类型化仓储模式,我们实现了按属性名给任意表的任意列添加Where条件的功能,目前多条件默认采用AND逻辑。现在需要实现:同一属性对应多个值时,该属性的多条件改为OR逻辑;不同属性之间仍保持AND逻辑。现有代码通过循环调用AddWhereClause方法处理属性名与对应的值数组,请问如何修改该方法以实现需求?

现有代码

private static IQueryable<T> AddWhereClause(IQueryable<T> query, string propName, string propValue)
{
    ParameterExpression parameterExpression = Expression.Parameter(typeof(T), "e");
    Expression makePropPath = MakePropPath(parameterExpression, propName);

    ConstantExpression value = null;

    string dataPropertyType = typeof(T).GetProperties()
        .FirstOrDefault(pi => pi.Name == propName)?.PropertyType.FullName;

    if (dataPropertyType.Contains("System.String"))
    {
        value = Expression.Constant(propValue, typeof(string));
    }
    else if (dataPropertyType.Contains("System.Int"))
    {
        int? valueCast = Convert.ToInt32(propValue);
        value = Expression.Constant(valueCast, typeof(int?));
    }
    else if (dataPropertyType.Contains("System.Double"))
    {
        double? valueCast = Convert.ToDouble(propValue);
        value = Expression.Constant(valueCast, typeof(double?));
    }
    else if (dataPropertyType.Contains("System.Boolean"))
    {
        bool? valueCast = Convert.ToBoolean(propValue);
        value = Expression.Constant(valueCast, typeof(bool?));
    }

    BinaryExpression body = Expression.Equal(makePropPath, value);
    Expression<Func<T, bool>> predicateLambda = Expression.Lambda<Func<T, bool>>(body, parameterExpression);
    return query.Where(predicateLambda);
}

修改方案

核心思路是:让方法接受一个属性的多个值,将这些值对应的Equal表达式用Expression.OrElse组合成一个OR条件,再添加到查询中。不同属性的条件仍然通过多次调用方法保持AND逻辑(因为每次Where都是追加AND条件)。

具体修改步骤:

  • 修改方法签名,将单值参数改为多值参数,支持传入同一属性的多个值
  • 处理空值或空集合的边界情况,直接返回原查询
  • 针对属性类型批量转换值,生成对应类型的常量表达式
  • 用Expression.OrElse将多个Equal表达式组合成OR逻辑链
  • 生成Lambda表达式并追加到查询的Where条件中

修改后的完整代码

private static IQueryable<T> AddWhereClause(IQueryable<T> query, string propName, IEnumerable<string> propValues)
{
    // 空值或空集合直接返回原查询
    if (propValues == null || !propValues.Any())
        return query;

    ParameterExpression parameterExpression = Expression.Parameter(typeof(T), "e");
    Expression propAccess = MakePropPath(parameterExpression, propName);
    var propertyInfo = typeof(T).GetProperties().FirstOrDefault(pi => pi.Name == propName);
    
    if (propertyInfo == null)
        return query;

    Type propType = propertyInfo.PropertyType;
    // 处理可空类型,获取底层类型
    Type underlyingType = Nullable.GetUnderlyingType(propType) ?? propType;

    List<Expression> equalExpressions = new List<Expression>();

    foreach (var propValue in propValues)
    {
        ConstantExpression value = null;
        try
        {
            // 根据属性类型转换值
            object convertedValue = Convert.ChangeType(propValue, underlyingType);
            // 如果原属性是可空类型,包装成可空常量
            if (Nullable.GetUnderlyingType(propType) != null)
            {
                value = Expression.Constant(convertedValue, propType);
            }
            else
            {
                value = Expression.Constant(convertedValue, underlyingType);
            }
        }
        catch
        {
            // 转换失败跳过该值,也可根据需求抛出异常
            continue;
        }

        // 构建属性 == 值的表达式
        equalExpressions.Add(Expression.Equal(propAccess, value));
    }

    // 没有有效表达式则返回原查询
    if (!equalExpressions.Any())
        return query;

    // 组合所有Equal表达式为OR逻辑
    Expression orBody = equalExpressions[0];
    for (int i = 1; i < equalExpressions.Count; i++)
    {
        orBody = Expression.OrElse(orBody, equalExpressions[i]);
    }

    Expression<Func<T, bool>> predicateLambda = Expression.Lambda<Func<T, bool>>(orBody, parameterExpression);
    return query.Where(predicateLambda);
}

关键说明

  • OR逻辑选择:用Expression.OrElse而非Expression.Or,前者对应C#的||短路逻辑,更适配EF的查询优化
  • 可空类型兼容:通过Nullable.GetUnderlyingType区分可空与非可空类型,保证常量表达式类型与属性匹配
  • 错误容错:捕获值转换失败的异常,避免单个无效值导致整个查询崩溃,可根据业务调整为抛出异常
  • 调用方式:同一属性的多个值只需一次传入方法;不同属性分别调用方法,自动保持AND逻辑

内容的提问来源于stack exchange,提问作者Stephen Himes

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.14 23:37:06