【问题标题】:How to translate this SQL query to a LINQ query in EF Core?如何将此 SQL 查询转换为 EF Core 中的 LINQ 查询?
【发布时间】:2019-04-23 16:21:47
【问题描述】:

我有下表:

Indicators(A INT, B INT, C INT, D INT, TimeInsertedLocal DateTime) . 

我有映射到此表的 EF Core 映射实体。

我需要将此 SQL 查询转换为 ef core Linq 等效查询。

SELECT A, B, C, D, TimeInsertedLocal
FROM Indicators
WHERE TimeInsertedLocal >= 
(   
    SELECT MAX(I.TimeInsertedLocal) 
    FROM Indicators AS I
) 

这是实体:

public class Indicator
{
    public int A { get; set; }
    public int B { get; set; }
    public int C { get; set; }
    public int D { get; set; }
    public DateTime TimeInsertedLocal { get; set; }
 }

如何编写 LINQ 查询,以便 EF Core 生成相同的查询或更好的查询以达到相同的结果?

【问题讨论】:

  • 你的相关实体类在哪里?
  • 一条记录怎么能大于MAX(TimeInsertedLocal)
  • TimeInsertedLocal 是插入行的日期时间。
  • 我更新了问题,它现在包括实体类。

标签: c# sql linq entity-framework-core


【解决方案1】:

实际上是一对一的翻译。

SQL 查询

SELECT A, B, C, D , TimeInsertedLocal
FROM Indicators
WHERE TimeInsertedLocal >= 
(   
    SELECT MAX(I.TimeInsertedLocal) 
    FROM Indicators AS I
)

EF Core LINQ 查询:

var indicators = dbContext.Set<Indicator>();
var query = indicators
    .Where(i => i.TimeInsertedLocal >= indicators.Max(i2 => (DateTime?)i2.TimeInsertedLocal));

EF Core 生成的 SQL 查询:

SELECT [i].[A], [i].[B], [i].[C], [i].[D], [i].[TimeInsertedLocal]
FROM [Indicators] AS [i]
WHERE [i].[TimeInsertedLocal] >= (
    SELECT MAX([i2].[TimeInsertedLocal])
    FROM [Indicators] AS [i2]
)

LINQ 查询中唯一的具体细节是 DateTime?Max 中的转换,否则 EF Core 将尝试模拟 LINQ Max 方法抛出行为并评估查询 client side

【讨论】:

  • 是的,你成功了。如果没有那个演员表,就会有两次到数据库服务器的往返,这很奇怪。
【解决方案2】:

当然,没有任何指标的 TimeInsertedLocal 值大于所有指标中 TimeInsertedLocal 的最大值。

但是,您可能有多个指标的值等于 TimeInsertedLocal 的最大值。

如果是这种情况,则需要将具有相同TimeInsertedLocal的Indicators分组,并取最大的组。

var indicatorsWithLargestTimeInsertedLocal = myDbContext.Indicators
    // make groups of Indicators with same TimeInsertedLocal:
    .GroupBy(indicator => indicator.TimeInsertedLocal)

    // put the group with the largest TimeInsertedLocal first:
    .OrderByDescending(group => group.Key)

    // The first group of indicators, is the group with the largest value of TimeInsertedLocal
    .FirstOrDefault();

如果您确定 TimeInsertedLocal 是唯一的,则不必 GroupBy,只会有一个具有最大 TimeInsertedLocal 的指标

var indicatorWithLargestTimeInsertedLocal = myDbContext.Indicators
    .OrderByDescending(indicator => indicator.TimeInsertedLocal)
    .FirstOrDefault();

【讨论】:

  • 这会将表格中的所有数据带入,然后在应用程序中对其进行过滤。我需要在数据库级别完成此操作。
  • 是什么让你这么认为?如果 myDbContext.Indicators 为IQueryable&lt;Indicator&gt;,则 GroupBy、OrderByDescending 和 FirstOrDefault 将执行AsQueryable,这意味着它们将由 DBMS 执行
  • @HaraldCoppoolse 目前 EF Core IQueryable 不保证 DBMS 的执行 - 请参阅 Client vs. Server EvaluationHow Queries Work。从您的帖子看来,您对 EF Core 的经验很少或根本没有。 EF Core 是与 EF6 完全不同的系统,因此您不能在那里应用 EF6 中的知识。
  • 你说得对,我在实体框架上试过。没注意是核心
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-06-14
  • 2016-01-23
  • 2022-01-22
  • 1970-01-01
  • 1970-01-01
  • 2012-10-11
相关资源
最近更新 更多