使用 EF Core 6.0 和 SQL Server 进行 GroupBy

Ton*_*org 7 c# sql-server entity-framework blazor ef-core-6.0

我有一个 Blazor Web 应用程序,它已经在现场工作了几个月。我想将数据库查询扩展到类似的“检测”组。

它是从 .NET 5 开始编写的,今天更新到 .NET 6,试图让它正常工作。

我想知道如何获取按TimeStamp(日期时间属性)排序的结果。我有一个使用内存数据库的工作示例,但生产将在 SQL Server 中进行。我不太擅长 SQL,但我在 Management Studio 中使用它一段时间了,但没有运气。

正确地注释了OrderByDescending()组的内容,但结果的顺序不正确。EF 翻译过程似乎完全删除了该行,它对生成的查询或结果集没有任何影响。

var results = context.Detections
//Line below makes no change ignored by SQL Server. Works when using in memory DB.
    //.OrderByDescending(det => det.TimeStamp) 
    .GroupBy(det => new
    {
        Year = det.TimeStamp.Year,
        Month = det.TimeStamp.Month,
        Day = det.TimeStamp.Day,
        Hour = det.TimeStamp.Hour,
    })
    .Select(grp => new
    {
        Count = grp.Count(),
        Detection = grp.OrderByDescending(det => det.TimeStamp).First(),
    })
//The following line will not translate
    //.OrderByDescending(det => det.Detection.TimeStamp)
    .ToList();
Run Code Online (Sandbox Code Playgroud)

如果其中任何一个很重要:

  • Visual Studio 2022 (4.8.04084)
  • .Net 6.0
  • SQL Server 2019 (15.0.2080.9)
  • *所有与 EF 相关的 NuGet 包均已更新至 6.0

编辑以澄清
上述代码段生成以下 SQL 查询。

SELECT [t].[c], [t0].[Id], [t0].[TimeStamp]
FROM (
    SELECT COUNT(*) AS [c], DATEPART(year, [d].[TimeStamp]) AS [c0], DATEPART(month, [d].[TimeStamp]) AS [c1], DATEPART(day, [d].[TimeStamp]) AS [c2], DATEPART(hour, [d].[TimeStamp]) AS [c3]
    FROM [Detections] AS [d]
    WHERE [d].[TimeStamp] > DATEADD(day, CAST(-16.0E0 AS int), GETUTCDATE())
    GROUP BY DATEPART(year, [d].[TimeStamp]), DATEPART(month, [d].[TimeStamp]), DATEPART(day, [d].[TimeStamp]), DATEPART(hour, [d].[TimeStamp])
) AS [t]
OUTER APPLY (
    SELECT TOP(1) [d0].[Id], [d0].[TimeStamp]
    FROM [Detections] AS [d0]
    WHERE ([d0].[TimeStamp] > DATEADD(day, CAST(-30.0E0 AS int), GETUTCDATE())) AND (((([t].[c0] = DATEPART(year, [d0].[TimeStamp])) AND ([t].[c1] = DATEPART(month, [d0].[TimeStamp]))) AND ([t].[c2] = DATEPART(day, [d0].[TimeStamp]))) AND ([t].[c3] = DATEPART(hour, [d0].[TimeStamp])))
    ORDER BY [d0].[TimeStamp] DESC
) AS [t0]
Run Code Online (Sandbox Code Playgroud)

它产生类似于以下的结果。注意不按时间排序。

1   628591  2021-11-02 14:34:06.0442966  
10  628601  2021-11-12 05:43:27.7015291  
150 628821  2021-11-12 21:59:27.6444236  
20  628621  2021-11-12 06:17:13.7798282  
50  628671  2021-11-12 15:17:23.8893856  
Run Code Online (Sandbox Code Playgroud)

如果我ORDER BY [t0].TimeStamp DESC在 Management Studio 中的 SQL 查询末尾添加,我会得到我正在寻找的结果(见下文)。我只需要知道如何在 LINQ 中编写它。

150 628821  2021-11-12 21:59:27.6444236  
50  628671  2021-11-12 15:17:23.8893856  
20  628621  2021-11-12 06:17:13.7798282  
10  628601  2021-11-12 05:43:27.7015291  
1   628591  2021-11-02 14:34:06.0442966  
Run Code Online (Sandbox Code Playgroud)

.OrderByDescending(det => det.Detection.TimeStamp)之前在最后添加的ToList()是我的第一个想法,但“无法翻译”。我需要对这些结果进行一些分页,所以我真的很想在 SQL 中进行排序。

Ton*_*org 2

对于任何将来关注这个问题的人。

我能够通过声明和填充属性并在最后TimeStamp使用来完成这项工作。OrderByDescending()我不确定这是否是最好的解决方案,但它确实解决了我的问题。

var results = context.Detections
    .GroupBy(det => new
    {
        Year = det.TimeStamp.Year,
        Month = det.TimeStamp.Month,
        Day = det.TimeStamp.Day,
        Hour = det.TimeStamp.Hour,
    })
    .Select(grp => new
    {
        Count = grp.Count(),
        TimeStamp = grp.OrderByDescending(det => det.TimeStamp).First().TimeStamp,
        Detection = grp.OrderByDescending(det => det.TimeStamp).First(),
    })
    .OrderByDescending(det => det.TimeStamp)
    .ToList();
Run Code Online (Sandbox Code Playgroud)