如何将这个 SQL 查询转换为 EF Core 中的 LINQ 查询?

3
我有以下表格:
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生成相同的查询或更好的查询来实现相同的结果?

你的相关实体类在哪里? - TanvirArjel
一条记录怎么可能比 MAX(TimeInsertedLocal) 还要大呢? - SS_DBA
TimeInsertedLocal 是插入行的日期时间。 - Ondama papaoutai
我更新了问题,现在包括实体类。 - Ondama papaoutai
2个回答

5

这就是字面上的一对一翻译。

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查询中唯一具体的细节是Max内部的DateTime?转换,否则EF Core会尝试模拟LINQ Max方法的抛出行为,并在客户端评估查询。(参考链接)

是的,你做得很好。而且如果没有那个转换,就会有两次往返到数据库服务器,这很奇怪。 - Ondama papaoutai

2

当然,不存在值大于所有指标的TimeInsertedLocal的指标。

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

如果是这种情况,你需要将具有相同TimeInsertedLocal的指标分组,并选择具有最大值的组。

最初的回答

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();

这会将表中的所有数据带入应用程序,然后在应用程序中进行筛选。我需要在数据库层面完成这个操作。 - Ondama papaoutai
你为什么这么认为呢?如果我的DbContext.Indicators是IQueryable<Indicator>,那么 GroupBy、OrderByDescending 和 FirstOrDefault 将会被执行 AsQueryable,这意味着它们将由DBMS执行。 - Harald Coppoolse
1
@HaraldCoppoolse 目前 EF Core 的 IQueryable 不能保证 DBMS 执行 - 请参阅 客户端 vs. 服务器端评估查询工作原理。从您的帖子来看,似乎您对 EF Core 没有或很少经验。EF Core 是完全不同于 EF6 的系统,因此您无法将您在 EF6 中的知识应用到 EF Core 上。 - Ivan Stoev
你是对的,我在实体框架上尝试过了。没有注意到它是核心版。 - Harald Coppoolse

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接