如何在LINQ中建立一个动态OR查询

本文关键字:一个 动态 查询 OR LINQ 建立 | 更新日期: 2023-09-27 18:04:50

我试图动态创建一个链接where子句。现在,创造像SELECT Product WHERE x = 123 AND y = 349 AND w = 948这样的东西是没有问题的。我只是添加了额外的Where过滤器。products = products.Where(product => product.Property == 123);

但是现在我有一个未知的值,应该用OR操作符进行测试。SQL应该像SELECT Product WHERE x = 123 OR x = 499 OR x = 998 .. and n more OR's

如何在LINQ中建立一个动态OR查询

创建一个要检查的数字列表,并执行如下操作:

var idsToCheck = new List<int>{123, 789, 654}; //Build from dynamic list
products = products.Where(x => idsToCheck.Contains(x.Id));

如果需要,上面的v和w可以被复制

var idsToCheck = new List<int>{123, 789, 654}; //Build from dynamic list
products = products.Where(x => idsToCheck.Contains(x.Id));
var propertyToCheck = new List<int>{123, 789, 654};//Build from dynamic list
products = products.Where(x => propertyToCheck.Contains(x.Property));
var numberToCheck = new List<int>{123, 789, 654};
products = products.Where(x => numberToCheck.Contains(x.Number));

如果你要检查的值已经作为枚举传入,那么你不需要构建你的xxxToCheck集合。您可以简单地对原始

执行.Contains

你可以在列表中使用contains或者像这样使用等式:

  products.Where(product => (product.Property == 123) || (product.Property == 499) || (product.Property == 998));

如果您想要从多个where子句组合一个OR查询,那么您实际上需要在where子句中组合谓词。毕竟,链接where子句应该是AND。

所以,如果你有以下谓词:

Func<Product, bool> w1 = p => p.x == 123;
Func<Product, bool> w2 = p => p.y == 349;
Func<Product, bool> w3 = p => p.w == 948;
Func<Product, bool> w4 = p => p.Property == 123;
Func<Product, bool> w5 = p => p.x == 499;
Func<Product, bool> w6 = p => p.x == 998;

您可以定义以下扩展方法来OR它们:

public static Func<T, bool> Or<T>(this Func<T, bool> @this, Func<T, bool> that)
{
    return t => @this(t) || that(t);
}

现在你可以写:

var products1 = products.Where(w1.Or(w5).Or(w6));
var products2 = products.Where(
    ((Func<Product, bool>)(p => p.x == 123))
        .Or(p => p.y == 349)
        .Or(p => p.Property == 123));

如果你想使用子句列表,那么添加这个扩展方法:

public static Func<T, bool> Or<T>(this IEnumerable<Func<T, bool>> @this)
{
    return @this.Aggregate((Func<T, bool>)(t => true), (a, t) => a.Or(t));
}

现在你可以写:

var predicates = new List<Func<Product, bool>>()
{
    p => p.x == 123,
    p => p.w == 948,
    p => p.Property == 123,
    p => p.x == 998,
};
var products3 = products.Where(predicates.Or());

如果你是针对IQueryable<T>提供商写的,那么你需要使用Expression<Func<Product, bool>>,而不仅仅是Func<Product, bool>

那么你需要这些扩展方法:

public static Expression<Func<T, bool>> Or<T>(
    this Expression<Func<T, bool>> @this,
    Expression<Func<T, bool>> that)
{
    var param =
        Expression
            .Parameter(typeof(T), "t");
    var body =
        Expression
            .Or(
                Expression
                    .Invoke(@this, param),
                Expression
                    .Invoke(that, param));
    return
        Expression
            .Lambda<Func<T, bool>>(body, param);
}
public static Expression<Func<T, bool>> Or<T>(
    this IEnumerable<Expression<Func<T, bool>>> @this)
{
    return @this.Aggregate((Expression<Func<T, bool>>)(t => true), (a, t) => a.Or(t));
}

调用代码仍然是相同的:

var predicatesX = new List<Expression<Func<Product, bool>>>()
{
    p => p.x == 123,
    p => p.w == 948,
    p => p.Property == 123,
    p => p.x == 998,
};
var products3X = products.Where(predicatesX.Or());

这是你要找的吗?