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

如何基于用户输入构建带OR运算符的动态LINQ查询(EF Core DynamicLinq)

基于Microsoft.EntityFrameworkCore.DynamicLinq实现OR逻辑的动态LINQ查询

现有实现与需求

我使用Microsoft.EntityFrameworkCore.DynamicLinq库,已通过链式调用Where实现了AND逻辑的动态LINQ查询,核心代码如下:

实体与查询类定义

public class FilterAnd
{
    public string Field { get; set; } = string.Empty;
    public string Value { get; set; } = string.Empty;
    public Criteria Criteria { get; set; }

    public string GetLinqQuery() { 
        string query = string.Empty;
        switch (this.Criteria)
        {
            case Criteria.Equal:
                query = $"{Field} == @0";
                break;
            case Criteria.NotEqual:
                query = $"{Field} != @0";
                break;
            case Criteria.GreaterThan:
                query = $"{Field} > @0";
                break;
            case Criteria.LessThan:
                query = $"{Field} < @0";
                break;
            case Criteria.GreaterThanOrEqual:
                query = $"{Field} >= @0";
                break;
            case Criteria.LessThanOrEqual:
                query = $"{Field} <= @0";
                break;
            case Criteria.Like:
            case Criteria.In:
            case Criteria.NotLike:
            case Criteria.NotIn:
                query = $"!{Field}.Contains(@0)";
                break;
            case Criteria.IsNull:
                query = $"{Field} == null";
                break;
            case Criteria.IsNotNull:
                query = $"{Field} != null";
                break;
        }
        return query;
    }
}

public class Search
{
    public List<FilterAnd> FiltersAnd { get; set; } = new List<FilterAnd>();
    public List<OrderBy> OrderBy { get; set; } = new List<OrderBy>();
    public int Skip { get; set; } = 0;
    public int Take { get; set; } = 2000;
}

AND逻辑查询构建方法

public IQueryable<T> PrepareQuerySearch(Search search)
{
    string delimiter = "§^_^§";
    var query = _dbContext.Set<T>().AsQueryable();
    foreach (var filter in search.FiltersAnd)
    {
        switch (filter.Criteria)
        {
            case Criteria.In:
            case Criteria.NotIn:
                query = query.Where(filter.GetLinqQuery(), filter.Value.Split(delimiter));
                break;
            default:
                query = query.Where(filter.GetLinqQuery(), filter.Value);
                break;
        }
    }
    return query;
}

现在需要将search.FiltersAnd替换为search.FiltersOr,实现OR逻辑的动态查询,希望找到比手动构建LINQ Expression更简便的方案。


2023.01.10 更新

目前我尝试通过LINQ Expression实现,但工作量较大,以下是Equal条件的实现示例:

public static IQueryable<T> WhereEqual<T>(this IQueryable<T> source, string propertyName, string propertyValue)
{
    var param = Expression.Parameter(typeof(T));
    var prop = typeof(T).GetProperty(propertyName);
    var condition =
        Expression.Lambda<Func<T, bool>>(
            Expression.Equal(
                Expression.Property(param, propertyName),
                Expression.Constant(propertyValue, prop.PropertyType)
            ),
            param
        );
    return source.Where(condition);
}

简便实现OR逻辑的方案

利用Microsoft.EntityFrameworkCore.DynamicLinq的字符串查询特性,将所有OR条件拼接为一个带||运算符的查询语句,一次性传入Where方法即可,无需手动构建Expression。

步骤1:调整实体类

将Search类中的FiltersAnd替换为FiltersOr,同时复用原FilterAnd的结构(或重命名为FilterOr):

public class FilterOr
{
    public string Field { get; set; } = string.Empty;
    public string Value { get; set; } = string.Empty;
    public Criteria Criteria { get; set; }

    // 复用原GetLinqQuery方法逻辑
    public string GetLinqQuery() { 
        string query = string.Empty;
        switch (this.Criteria)
        {
            case Criteria.Equal:
                query = $"{Field} == @0";
                break;
            case Criteria.NotEqual:
                query = $"{Field} != @0";
                break;
            case Criteria.GreaterThan:
                query = $"{Field} > @0";
                break;
            case Criteria.LessThan:
                query = $"{Field} < @0";
                break;
            case Criteria.GreaterThanOrEqual:
                query = $"{Field} >= @0";
                break;
            case Criteria.LessThanOrEqual:
                query = $"{Field} <= @0";
                break;
            case Criteria.Like:
            case Criteria.In:
            case Criteria.NotLike:
            case Criteria.NotIn:
                query = $"!{Field}.Contains(@0)";
                break;
            case Criteria.IsNull:
                query = $"{Field} == null";
                break;
            case Criteria.IsNotNull:
                query = $"{Field} != null";
                break;
        }
        return query;
    }
}

public class Search
{
    public List<FilterOr> FiltersOr { get; set; } = new List<FilterOr>();
    public List<OrderBy> OrderBy { get; set; } = new List<OrderBy>();
    public int Skip { get; set; } = 0;
    public int Take { get; set; } = 2000;
}

步骤2:重构查询构建方法

修改PrepareQuerySearch,收集所有OR条件的查询字符串和参数,拼接成一个完整的OR表达式:

public IQueryable<T> PrepareQuerySearch(Search search)
{
    string delimiter = "§^_^§";
    var query = _dbContext.Set<T>().AsQueryable();
    
    if (search.FiltersOr?.Any() != true)
        return query;

    var orConditions = new List<string>();
    var parameters = new List<object>();

    foreach (var filter in search.FiltersOr)
    {
        // 替换参数占位符为当前参数索引,避免重复使用@0导致参数混淆
        var indexedQuery = filter.GetLinqQuery().Replace("@0", $"@{parameters.Count}");
        
        switch (filter.Criteria)
        {
            case Criteria.In:
            case Criteria.NotIn:
                parameters.Add(filter.Value.Split(delimiter));
                break;
            default:
                parameters.Add(filter.Value);
                break;
        }

        orConditions.Add(indexedQuery);
    }

    // 用||拼接所有OR条件
    var combinedOrQuery = string.Join(" || ", orConditions);
    query = query.Where(combinedOrQuery, parameters.ToArray());

    return query;
}

方案优势

  • 复用原有GetLinqQuery方法的逻辑,改动极小
  • 无需手动处理Expression的拼接逻辑,代码简洁易维护
  • 完全利用DynamicLinq的特性,保持查询的可翻译性(能正确转换为SQL)

内容的提问来源于stack exchange,提问作者Tim Allemann

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.05 08:22:50