6

如果您向当前查询添加更多限制,您可以轻松地在 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;
4

2 回答 2

3

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

添加以下表达式扩展:

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)

这样,您可以将 lambdas 保存在一个集合中并循环遍历它们。

于 2018-03-23T20:00:41.500 回答
2

感谢 Raphaël Althaus 提供了以下链接:

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

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

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

于 2013-09-03T17:03:51.013 回答