【问题标题】:Composing an OR query with EF Core使用 EF Core 编写 OR 查询
【发布时间】:2019-02-27 04:30:20
【问题描述】:

我有一个 DbQuery,我试图根据用户提供的各种(可选)参数进行过滤。我正在尝试使用 LINQ 编写查询来解决这个问题,但遇到了障碍,所以这是一种两方合作。

Postgres: 我正在使用 postgres,所以我有一个数组列,并且我希望能够基本上执行 useCaseArray && entity.useCases。但是,EF 提供程序目前不支持此功能。

如果可以避免的话,我不想直接用原始 sql 编写整个内容,所以我想我可以做一个非常丑陋的 WHERE:

WHERE (useCases.Contains(x) || useCases.Contains(y) ...)

但是我不知道如何使用 LINQ 来组合。我知道你可以内联做 OR,比如

query.Where(item => item.cases.Contains(x) || item.cases.Contains(y))

但是我不能这样写,因为我需要遍历/循环 包含我的 Xs 和 Ys 的数组。有谁知道我该怎么做?

foreach(var usecase in request.UseCases) 
{
  query = query.Where(item => item.UseCases.Contains(usecase));
}

当我想要整个子集成为一个 OR 时,这将只生成一长串 AND。

我希望我已经设法适当地解释了这一点!或者,我希望能够在原始 SQL 中注入单个 WHERE 子句组件,但我认为这会导致 EF Core 爆炸,而且听起来 FromSQL 不支持 WHERE just 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.

我认为这对我来说没问题,但原来的问题仍然存在,我希望它在数据库上运行。

【问题讨论】:

  • 任何谓词构建器助手都可以做 OR 工作——比如 thisthis,甚至是 classical 等。
  • 德普。我以前使用过其中一种,但我只是假设由于某种原因它不适用于核心。我会试一试,谢谢。
  • 所以,跟进,使用这个工作 - 技术上 - 但 EF Core 抱怨它无法评估它并在本地而不是在数据库上进行过滤。我不确定这在技术上是一件坏事——对我来说——但它并不能真正解决我提出的问题。
  • 是的,客户端评估是 EF Core 的缺陷之一 - 从技术上讲它“有效”,但实际上它没有。 item.UserCases 的类型是什么?我们可以看到示例实体模型吗?此外,如果您知道如何使用原始 SQL,那么请使用原始 SQL 进行操作 - db.UseCasesFromSql("SELECT * FROM … WHERE ...) 返回 IQueryable&lt;UserCase&gt;composable - 您可以添加 Include,以及几乎任何普通的 LINQ 查询运算符。
  • x 和 y 是整数,抱歉,我不确定在这种情况下它是否超级重要,因为如果它们是字符串,情况将是相同的。 @IvanStoev FromSql 实际上工作正常,如果不是我预期的那样,我会再做一次更新!

标签: c# entity-framework-core npgsql


【解决方案1】:

所以在一些有用的 cmets 之后我尝试了 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% 喜欢这样,因为现在我的服务知道我的数据库表和字段名称,这几乎使 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 驱动程序之前,这可能是我能做的最好的事情。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-04-29
    • 2020-03-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-01-09
    • 2019-04-28
    相关资源
    最近更新 更多