如果向当前查询添加更多限制,则可以在 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;
最佳答案
另一个可能的解决方案,特别是当有人不想使用外部库时,使用表达式树。
添加以下表达式扩展:
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 保存在一个集合中并循环遍历它们。
关于在用 OR 连接的 where 子句中使用动态谓词的 linq 查询,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18596847/