带有动态谓词的linq查询在由OR连接的where子句中

时间:2013-09-03 16:08:49

标签: linq lambda expression

如果向当前查询添加更多限制,则可以在c#中轻松创建动态查询。

var list = new List<Item>();
var q = list.AsQueryable();
q = q.Where(x => x.Size == 3);
q = q.Where(x => x.Color == "blue");

在这种情况下,添加每个新谓词与前一个执行AND操作。之前的结果相当于:

q = list.Where(x => x.Size == 3 && x.Color == "blue");

是否可以使用OR代替AND来实现相同的结果?

q = list.Where(x => x.Size == 3 || x.Color == "blue");

我们的想法是使用OR运算符连接可变数量的表达式。

预期结果需要写入一些与以下伪代码类似的内容:

var conditions = new List<Func<Item, bool>>();

然后迭代条件来构建类似的东西:

foreach(var condition in conditions)
    finalExpression += finalExpression || condition;

2 个答案:

答案 0 :(得分:1)

感谢RaphaëlAlthaus给出了以下链接:

http://www.albahari.com/nutshell/predicatebuilder.aspx

谓词构建器是解决方案。您可以使用它从Nuget安装LinqKit。在该URL中,您还可以找到此类的实现。

注意:为了使这个工作与LinqToSql或LinqToEntities一起使用,必须使用“AsExpandable()”方法转换IQueriable对象,对于内存对象,它不是必需的

答案 1 :(得分:1)

另一个可能的解决方案,特别是当有人不想使用外部库时,使用表达式树。

添加以下表达式扩展名:

public static Expression<Func<T, bool>> Or<T>(
    this Expression<Func<T, bool>> expr1, 
    Expression<Func<T, bool>> expr2)
{
    var invokedExpr = Expression.Invoke(expr2, expr1.Parameters);
    return Expression.Lambda<Func<T, bool>>(
        Expression.OrElse(expr1.Body, invokedExpr), expr1.Parameters);
}

作为一个例子,假设你有一个Container实体,它有InnerContainer嵌套实体,有两个属性Name和Id。然后您可以通过以下方式使用它:

Expression<Func<Container, bool>> whereQuery = c => c.InnerContainer.Name == "Name1";
whereQuery = whereQuery.Or(c => c.InnerContainer.Name == "Name2");
whereQuery = whereQuery.Or(c => c.InnerContainer.Id == 0);
var result = query
    .Where(whereQuery)
    .ToList();

实现此类查询将导致以下SQL:

SELECT [x].[Id], [x].[InnerContainerId]
FROM [Containers] AS [x]
LEFT JOIN [InnerContainer] AS [x.InnerContainer] ON [x].[InnerContainerId] = [x.InnerContainer].[Id]
WHERE [x.InnerContainer].[Name] IN (N'Name1', N'Name2') OR ([x].[InnerContainerId] = 0)

这样你就可以在一个集合中持有lambda并循环遍历它们。