【问题标题】:linq query with dynamic predicates in where clause joined by OR在由 OR 连接的 where 子句中具有动态谓词的 linq 查询
【发布时间】:2013-09-03 16:08:49
【问题描述】:

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

【问题讨论】:

  • 您使用 AsQueryable 有什么原因吗? (它在答案方面有所不同,有点......)
  • 是的,我最终需要使用查询访问数据库,因此它应该由数据库提供商正确翻译。虽然,我对 IEnumerable 的解决方案很感兴趣
  • 看看 PredicateBuilder :albahari.com/nutshell/predicatebuilder.aspx

标签: linq lambda expression


【解决方案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)

通过这种方式,您可以将 lambdas 保存在一个集合中并循环遍历它们。

【讨论】:

    【解决方案2】:

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

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

    谓词生成器是解决方案。您可以使用它从 Nuget 安装 LinqKit。在那个 url 你也可以找到这个类的实现。

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

    【讨论】:

      猜你喜欢
      • 2022-11-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-01-15
      • 1970-01-01
      • 2020-12-01
      • 1970-01-01
      相关资源
      最近更新 更多