c# - C# Linq:将多个 .Where() 与 *OR* 子句组合
问题描述
我一直在搜索我当前的问题,但我找不到解决该问题的真正答案。
我正在尝试构建一个生成以下 SQL 的 LINQ 查询:
SELECT * FROM TABLE WHERE (Field1 = X, Field2 = Y ... ) or (Field3 = Z)
在正常情况下,我会这样做:
Object.Where(c => (c.Field1 == X && c.Field2 == Y) || (c.Field3 == Z))
我不能使用这种方法,因为查询是通过使用多个.Where()
调用构建的。
举个例子:
// This is a short example, the real world situation has 20 fields to check and they are all connected with an AND.
if (model.Field1.HasValue)
{
Query = Query.Where(c => c.Field1 == X)
}
if (model.Field2.HasValue)
{
Query = Query.Where(c => c.Field2 == X)
}
[...] like 20 more of these .Where() calls.
这就是我变得复杂的原因。所有这些.Where()
调用都在构建一个与 连接的 Linq 查询AND
,这很好。
我如何让他们使用括号执行并OR
使用 API 添加一个简单的现在?
有没有办法将谓词保存在一些变量中,这样我就可以做出类似的事情:
Query = Query.Where(c => previousPredicates || c.Field3 == X)
或者如何解决这个问题?
我认为这个特定问题必须有一个好的解决方案,而且我不是唯一需要它的人,但我绝对不确定如何实现它。
PS:我无法真正删除多个.Where()
调用,并且直接编写 SQL 也不是一种选择。
编辑
StackOverflow 想让我说出为什么我的问题与其他问题不同。嗯,事情是关于Parentheses
。我不想.Where()
用一个 OR 子句连接所有内容,我想在所有查询都被括号括起来时留下它们AND
并添加另一个OR
子句。AND
解决方案
如果您想以编程方式构建查询并让它在 SQL 服务器上执行,而不是获取所有记录并在内存中查询,则需要使用Expression
类上的一组静态方法并使用这些方法构建查询。在您的示例中:
public class Query // this will contain your 20 fields you want to check against
{
public int? Field1; public int? Field2; public int? Field3; public int Field4;
}
public class QueriedObject // this is the object representing the database table you're querying
{
public int QueriedField;
}
public class Program
{
public static void Main()
{
var queryable = new List<QueriedObject>().AsQueryable();
var query = new Query { Field2 = 1, Field3 = 4, Field4 = 2 };
// this represents the argument to your lambda expression
var parameter = Expression.Parameter(typeof(QueriedObject), "qo");
// this is the "qo.QueriedField" part of the resulting expression - we'll use it several times later
var memberAccess = Expression.Field(parameter, "QueriedField");
// start with a 1 == 1 comparison for easier building -
// you can just add further &&s to it without checking if it's the first in the chain
var expr = Expression.Equal(Expression.Constant(1), Expression.Constant(1));
// doesn't trigger, so you still have 1 == 1
if (query.Field1.HasValue)
{
expr = Expression.AndAlso(expr, Expression.Equal(memberAccess, Expression.Constant(query.Field1.Value)));
}
// 1 == 1 && qo.QueriedField == 1
if (query.Field2.HasValue)
{
expr = Expression.AndAlso(expr, Expression.Equal(memberAccess, Expression.Constant(query.Field2.Value)));
}
// 1 == 1 && qo.QueriedField == 1 && qo.QueriedField == 4
if (query.Field3.HasValue)
{
expr = Expression.AndAlso(expr, Expression.Equal(memberAccess, Expression.Constant(query.Field3.Value)));
}
// (1 == 1 && qo.QueriedField == 1 && qo.QueriedField == 4) || qo.QueriedField == 2
expr = Expression.OrElse(expr, Expression.Equal(memberAccess, Expression.Constant(query.Field4)));
// now, we combine the lambda body with the parameter to create a lambda expression, which can be cast to Expression<Func<X, bool>>
var lambda = (Expression<Func<QueriedObject, bool>>) Expression.Lambda(expr, parameter);
// you can now do this, and the Where will be translated to an SQL query just as if you've written the expression manually
var result = queryable.Where(lambda);
}
}
推荐阅读
- aws-lambda - AWS Serverless:处理源自 AWS 外部的 JMS 源
- python - pandas 按包含数字和字母的列对数据帧进行排序
- python - 正确读取 JSON 文件
- sql - TSQL 最小和最大日期
- zsh - 如何在 zsh shell 中使用“setenv”命令?
- python - python将json对象转换为列表以验证内容
- python - scrapy 不会抓取父 URL
- python - 计数或标记数据框列达到条件的次数
- javascript - Javascript淡化彩色图像和背景
- python - 使用 matplotlib 绘制玩 tictactoe 的智能体的平均学习曲线