Entity Framework Core 3 模拟 PARTITION BY

Dem*_*sch 2 c# entity-framework-core

我正在尝试使用 EF Core 3 检索每个组的最新记录,但我想出的每个可能的 LINQ 查询都以InvalidOperationException异常结束Processing of the LINQ expression '...' by 'NavigationExpandingExpressionVisitor' failed. This may indicate either a bug or a limitation in EF Core

根据在 EF Core 2.2 中工作的一些答案,这个查询应该可以解决问题,但它没有

from lfv in dbo.ListingFlagValues
group lfv by lfv.ListingId into groups
select groups.OrderByDescending(x => x.Timestamp).FirstOrDefault();
Run Code Online (Sandbox Code Playgroud)

我尝试过的另一种选择是

db.ListingFlagValues.GroupBy(x => x.Listing)
  .Select(x => new { Group = x, MaxTimestamp = x.Max(y => y.Timestamp) })
  .SelectMany(x => x.Group.Select(y => new { y.ListingId, ValueId = y.NewFlagValueId, y.Timestamp, x.MaxTimestamp }))
  .Where(x => x.Timestamp == x.MaxTimestamp);
Run Code Online (Sandbox Code Playgroud)

我试图实现的行为类似于以下查询

SELECT
    ListingId,
    NewFlagValueId AS ValueId
FROM
    (SELECT
        ListingFlagValues.ListingId,
        NewFlagValueId,
        [Timestamp],
        MAX([Timestamp]) OVER (PARTITION BY  ListingFlagValues.ListingId) AS MaxTimestamp
    FROM
        ListingFlagValues        
    WHERE 
        FlagId = 1) as FlagValues
WHERE [Timestamp] = [MaxTimestamp]
Run Code Online (Sandbox Code Playgroud)

Iva*_*oev 10

这里的关键是异常消息中的“这可能表示 EF Core中的错误或限制”(将“可能表示”读作“表示”)。虽然 EF Core 3.0 改进了查询翻译,但它仍然不支持许多查询模式,尤其是在GroupBy. 并且由于它还删除了客户端评估,因此在 2.x 中由于静默客户端评估而工作的查询现在只是失败了。

另一方面,EF Core 3.0通过利用SQL 构造改进了组模式中最后一项的翻译ROW_NUMBER OVER (PARTITION BY。但是它不适用于GroupBy结果,因此您必须通过使用Distinct键查询和值相关子查询手动进行分组。

例如,以下 LINQ 查询

from listingId in db.ListingFlagValues.Select(x => x.ListingId).Distinct()
from lfv in db.ListingFlagValues
    .Where(x => x.ListingId == listingId)
    .OrderByDescending(e => e.Timestamp)
    .Take(1)
select lfv
Run Code Online (Sandbox Code Playgroud)

使用以下 SQL 成功翻译并执行

from listingId in db.ListingFlagValues.Select(x => x.ListingId).Distinct()
from lfv in db.ListingFlagValues
    .Where(x => x.ListingId == listingId)
    .OrderByDescending(e => e.Timestamp)
    .Take(1)
select lfv
Run Code Online (Sandbox Code Playgroud)