简体   繁体   English

Entity Framework Core 3 模拟 PARTITION BY

[英]Entity Framework Core 3 emulate PARTITION BY

I'm trying to retrieve the latest record for every group using EF Core 3 but every possible LINQ query I came up with ends up with the InvalidOperationException exception Processing of the LINQ expression '...' by 'NavigationExpandingExpressionVisitor' failed. This may indicate either a bug or a limitation in EF Core我正在尝试使用 EF Core 3 检索每个组的最新记录,但我想出的每个可能的 LINQ 查询都Processing of the LINQ expression '...' by 'NavigationExpandingExpressionVisitor' failed. This may indicate either a bug or a limitation in EF CoreInvalidOperationException异常处理失败。 Processing of the LINQ expression '...' by 'NavigationExpandingExpressionVisitor' failed. This may indicate either a bug or a limitation in EF Core . Processing of the LINQ expression '...' by 'NavigationExpandingExpressionVisitor' failed. This may indicate either a bug or a limitation in EF Core

According to some answers that worked in EF Core 2.2 this query should did the trick but it didn't根据在 EF Core 2.2 中有效的一些答案,这个查询应该可以解决问题,但它没有

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

One more option I've tried was我尝试过的另一种选择是

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

The behavior I'm trying to achieve is like in the following query我试图实现的行为类似于以下查询

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]

The key here is "This may indicate either a bug or a limitation in EF Core" in the exception message (read "may indicate" as "indicates ").这里的关键是异常消息中的“这可能表示 EF Core 中的错误或限制” (将“可能表示”读作“表示”)。 While EF Core 3.0 has improved the query translation, it still doesn't support many query patterns, especially on the result of GroupBy .虽然 EF Core 3.0 改进了查询翻译,但它仍然不支持许多查询模式,尤其是在GroupBy的结果上。 And since it also removed client evaluation, queries which worked in 2.x because of silent client evaluation now are simply failing.而且由于它还删除了客户端评估,因此由于静默客户端评估而在 2.x 中有效的查询现在只是失败了。

From the other side EF Core 3.0 has improved translation of the last item in a group pattern by utilizing the ROW_NUMBER OVER (PARTITION BY SQL construct. However it doesn't work for GroupBy results, so you have to do the grouping manually by using Distinct query for keys and correlated subquery for values.另一方面,EF Core 3.0 通过利用ROW_NUMBER OVER (PARTITION BY SQL 构造改进了组模式中最后一项的翻译。但是它不适用于GroupBy结果,因此您必须使用Distinct手动进行分组查询键和相关子查询的值。

For instance, the following LINQ query例如,下面的 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

translates and executes successfully using the following SQL使用以下 SQL 成功翻译并执行

  SELECT [t1].[Id], [t1].[ListingId], [t1].[NewFlagValueId], [t1].[Timestamp]
  FROM (
      SELECT DISTINCT [l].[ListingId]
      FROM [ListingFlagValues] AS [l]
  ) AS [t]
  INNER JOIN (
      SELECT [t0].[Id], [t0].[ListingId], [t0].[NewFlagValueId], [t0].[Timestamp]
      FROM (
          SELECT [l0].[Id], [l0].[ListingId], [l0].[NewFlagValueId], [l0].[Timestamp], ROW_NUMBER() OVER(PARTITION BY [l0].[ListingId] ORDER BY [l0].[Timestamp] DESC) AS [row]
          FROM [ListingFlagValues] AS [l0]
      ) AS [t0]
      WHERE [t0].[row] <= 1
  ) AS [t1] ON [t].[ListingId] = [t1].[ListingId] 

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM