将 SQL ROW_NUMBER 转换为 Linq 会产生错误的翻译

问题描述 投票:0回答:1

我有以下 SQL 代码,我想转换为 Entity Framework Core 8 中的 Linq lambda 查询。

SELECT * FROM(
SELECT ROW_NUMBER() OVER (PARTITION BY StaffId,[Location] ORDER BY [Timestamp] DESC) AS rn, StaffId, Location, [Timestamp] 
FROM CountryStaff 
WHERE [Timestamp] >= 
            DATEADD(hour,-1, GETDATE())
            AND [Location] = 'USA'
)x  WHERE x.rn = 1

这是我的 Linq 代码。

var date = DateTime.UtcNow.AddHours(-1);
var filteredTransactions = CountryStaff
    .Where(t => t.Location == "USA" && t.Timestamp >= date)
    .OrderByDescending(t => t.Timestamp);

filteredTransactions
    .OrderByDescending(t => t.Timestamp)
    .Skip(0)
    .Take(1)
    .Select(t => new
    {
        StaffId = t.StaffId,
        Location = t.Location,
        Timestamp = t.Timestamp
    }).ToList();

执行此代码时,它会被翻译如下并产生错误的结果

DECLARE @p0 NVarChar(1000) = 'USA'
DECLARE @p1 DateTime = '2024-02-28 06:25:22.590'
DECLARE @p2 Int = 0
DECLARE @p3 Int = 1

SELECT [t2].[StaffId], [t2].[Location], [t2].[Timestamp]
FROM (
    SELECT [t1].[StaffId], [t1].[Timestamp], [t1].[Location], [t1].[ROW_NUMBER]
    FROM (
        SELECT ROW_NUMBER() OVER (ORDER BY [t0].[Timestamp] DESC, [t0].[Timestamp] DESC) AS [ROW_NUMBER], [t0].[StaffId], [t0].[Timestamp], [t0].[Location]
        FROM [CountryStaff] AS [t0]
        WHERE ([t0].[Location] = @p0) AND ([t0].[Timestamp] >= @p1)
        ) AS [t1]
    WHERE [t1].[ROW_NUMBER] BETWEEN @p2 + 1 AND @p2 + @p3
    ) AS [t2]
ORDER BY [t2].[ROW_NUMBER]

编辑

我尝试使用此代码。尽管翻译了不同的 sql 查询,但它运行良好。不幸的是,它需要 5 秒而不是 0.6 毫秒。

CountryStaff 
    .Where(t => t.Timestamp >= date && t.Location == "USA")
    .GroupBy(t => new { t.StaffId, t.Location })
    .Select(g => g.OrderByDescending(t => t.Timestamp).First())
    .ToList();
c# sql linq lambda entity-framework-core
1个回答
0
投票

试试这个

var currentTimeMinusOneHour = DateTime.UTC.AddHours(-1);
var result = CountryStaff
             .Where(cs => cs.Timestamp >= currentTimeMinusOneHour && cs.Location == "USA")
              .GroupBy(cs => new { cs.StaffId, cs.Location })
              .Select(g => new
                    {
                        RowNumber = g.OrderByDescending(x => x.Timestamp)
                                     .Select((x, index) => new { x, index })
                                     .FirstOrDefault()?.index + 1,
                        StaffId = g.Key.StaffId,
                        Location = g.Key.Location,
                        Timestamp = g.Max(x => x.Timestamp)
                    })
                    .Where(x => x.RowNumber == 1)
                    .ToList();
© www.soinside.com 2019 - 2024. All rights reserved.