Entity Framework Core 3 эмулирует PARTITION BY - PullRequest
1 голос
/ 09 ноября 2019

Я пытаюсь получить самую последнюю запись для каждой группы, используя 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();

Еще одна опция, которую я попробовал, была

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

Поведение, которое я пытаюсь выполнитьдостигается как в следующем запросе

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]

1 Ответ

2 голосов
/ 10 ноября 2019

Ключ здесь "Это может означать либо ошибку, либо ограничение в 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

успешно переводит и выполняет с использованием следующего 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] 
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...