使用 EF Core 编写 OR 查询
Composing an OR query with EF Core
我有一个 DbQuery,我试图根据用户提供的各种(可选)参数对其进行过滤。我正在尝试使用 LINQ 编写查询来解决这个问题,但遇到了障碍,所以这是一种两人合作的方式。
Postgres:
我正在使用 postgres,所以我有一个数组列,我希望能够基本上执行 useCaseArray && entity.useCases。但是,EF 提供程序目前不支持此功能。
如果我能避免的话,我不想在原始 sql 中编写整个内容,所以我想我可以像这样做一个非常丑陋的地方:
WHERE (useCases.Contains(x) || useCases.Contains(y) ...)
但是我不知道如何使用 LINQ 编写。我知道您可以内联执行 OR,例如
query.Where(item => item.cases.Contains(x) || item.cases.Contains(y))
但是我不能那样写,因为我需要 foreach/loop
包含我的 X 和 Y 的数组。有谁知道我该怎么做?
foreach(var usecase in request.UseCases)
{
query = query.Where(item => item.UseCases.Contains(usecase));
}
当我想要的是整个子集是一个 OR 时,这将只生成一长串 AND。
我希望我已经设法恰当地解释了这一点!或者,我希望能够在原始 SQL 中注入单个 WHERE 子句组件,但我认为这会导致 EF Core 爆炸,听起来 FromSQL 不支持 WHERE 只是SELECT.
更新:
根据评论,我尝试了这个:https://petemontgomery.wordpress.com/2011/02/10/a-universal-predicatebuilder/ 效果非常好:
var useCaseQuery = request.UseCases
.Select(useCase => PredicateBuilder.Create<MyEntity>(entity => entity.UseCases.Contains(useCase)))
.Aggregate(PredicateBuilder.Or);
query = query.Where(useCaseQuery);
这在某种程度上很棒,但 EF Core 仍然不喜欢它:
The LINQ expression 'where ({[assumption].UseCases => Contains(__useCase_3)} OrElse {[assumption].UseCases => Contains(__useCase_4)})' could not be translated and will be evaluated locally.
我想这对我来说没问题,但原来的问题仍然存在,我想在数据库上 运行。
所以在一些有用的评论之后我尝试了 FromSql
if (request.UseCases != null && request.UseCases.Count > 0)
{
// I know UseCases is a List<int> hence why I'm just joining without escaping.
query = query.FromSql("SELECT * FROM my_table WHERE ARRAY[" + String.Join(',', request.UseCases) + "] && use_cases");
}
我不是 100% 喜欢这样,因为现在我的服务知道我的数据库 table 和字段名称,这几乎使 ORM 的目的无效。然而对于这个特定的案例,它满足了我的需要,我可以继续这样写:
if (request.Groups != null && request.Groups.Count > 0)
{
query = query.Where(data => request.Groups.Contains(data.GroupId));
}
if (!String.IsNullOrWhiteSpace(request.Title))
{
query = query.Where(data => EF.Functions.ILike(data.Name, $"%{request.Title}%"));
}
产生的SQL是这样的:
SELECT my_table.classes, my_table."group", my_table.group_id, my_table.id, my_table.name, my_table.use_cases
FROM (
SELECT * FROM my_table WHERE ARRAY[7,4] && use_cases
) AS assumption
WHERE my_table.group_id IN (7) AND (my_table.name ILIKE @__Format_3 ESCAPE '' = TRUE)
ORDER BY my_table.name DESC
在更新 Postgres EF Core 驱动程序之前,这可能是我能做的最好的事情了。
我有一个 DbQuery,我试图根据用户提供的各种(可选)参数对其进行过滤。我正在尝试使用 LINQ 编写查询来解决这个问题,但遇到了障碍,所以这是一种两人合作的方式。
Postgres: 我正在使用 postgres,所以我有一个数组列,我希望能够基本上执行 useCaseArray && entity.useCases。但是,EF 提供程序目前不支持此功能。
如果我能避免的话,我不想在原始 sql 中编写整个内容,所以我想我可以像这样做一个非常丑陋的地方:
WHERE (useCases.Contains(x) || useCases.Contains(y) ...)
但是我不知道如何使用 LINQ 编写。我知道您可以内联执行 OR,例如
query.Where(item => item.cases.Contains(x) || item.cases.Contains(y))
但是我不能那样写,因为我需要 foreach/loop 包含我的 X 和 Y 的数组。有谁知道我该怎么做?
foreach(var usecase in request.UseCases)
{
query = query.Where(item => item.UseCases.Contains(usecase));
}
当我想要的是整个子集是一个 OR 时,这将只生成一长串 AND。
我希望我已经设法恰当地解释了这一点!或者,我希望能够在原始 SQL 中注入单个 WHERE 子句组件,但我认为这会导致 EF Core 爆炸,听起来 FromSQL 不支持 WHERE 只是SELECT.
更新:
根据评论,我尝试了这个:https://petemontgomery.wordpress.com/2011/02/10/a-universal-predicatebuilder/ 效果非常好:
var useCaseQuery = request.UseCases
.Select(useCase => PredicateBuilder.Create<MyEntity>(entity => entity.UseCases.Contains(useCase)))
.Aggregate(PredicateBuilder.Or);
query = query.Where(useCaseQuery);
这在某种程度上很棒,但 EF Core 仍然不喜欢它:
The LINQ expression 'where ({[assumption].UseCases => Contains(__useCase_3)} OrElse {[assumption].UseCases => Contains(__useCase_4)})' could not be translated and will be evaluated locally.
我想这对我来说没问题,但原来的问题仍然存在,我想在数据库上 运行。
所以在一些有用的评论之后我尝试了 FromSql
if (request.UseCases != null && request.UseCases.Count > 0)
{
// I know UseCases is a List<int> hence why I'm just joining without escaping.
query = query.FromSql("SELECT * FROM my_table WHERE ARRAY[" + String.Join(',', request.UseCases) + "] && use_cases");
}
我不是 100% 喜欢这样,因为现在我的服务知道我的数据库 table 和字段名称,这几乎使 ORM 的目的无效。然而对于这个特定的案例,它满足了我的需要,我可以继续这样写:
if (request.Groups != null && request.Groups.Count > 0)
{
query = query.Where(data => request.Groups.Contains(data.GroupId));
}
if (!String.IsNullOrWhiteSpace(request.Title))
{
query = query.Where(data => EF.Functions.ILike(data.Name, $"%{request.Title}%"));
}
产生的SQL是这样的:
SELECT my_table.classes, my_table."group", my_table.group_id, my_table.id, my_table.name, my_table.use_cases
FROM (
SELECT * FROM my_table WHERE ARRAY[7,4] && use_cases
) AS assumption
WHERE my_table.group_id IN (7) AND (my_table.name ILIKE @__Format_3 ESCAPE '' = TRUE)
ORDER BY my_table.name DESC
在更新 Postgres EF Core 驱动程序之前,这可能是我能做的最好的事情了。