Создать подзапрос для фильтрации по значению оконной функции - PullRequest
1 голос
/ 04 марта 2020

Я пытаюсь добавить функциональность ROW_NUMBER в EF Core и фильтровать по ней.

После добавления пользовательской функции она отлично работает в Select, но не работает в Where из-за неправильной формы SQL.

Linq:

var query = dbContext.OrderItems
    .Select(i => new
    {  
        i.Name,
        RowNumber = EF.Functions.RowNumber(i.ProductId)
    })
    .Where(i => i.RowNumber == 1);

Переводится в:

SELECT
   i.NAME,
   ROW_NUMBER() OVER(ORDER BY i.ProductId) AS RowNumber
FROM
   OrderItems AS i
WHERE
   ROW_NUMBER() OVER(ORDER BY i.ProductId) = CAST(1 AS bigint)

Ошибка:

Microsoft.Data.SqlClient.SqlException (0x80131904): Windowed functions can only appear in the SELECT or ORDER BY clauses.

Чтобы исправить это SQL , Мне нужно создать подзапрос:

SELECT
  t.NAME,
  t.RowNumber
FROM (
   SELECT
      i.NAME,
      ROW_NUMBER() OVER(ORDER BY i.ProductId) AS RowNumber
   FROM
      OrderItems AS i
) t
WHERE
  t.RowNumber = CAST(1 AS bigint)

Я нашел статью о том, как сделать это в EF Core 2.

Возможно, самый простой способ - это ввести метод, который дает EF подсказку, что предыдущий запрос должен быть подзапросом. К счастью, у нас не так много, потому что внутри метод AsQueryable (или, скорее, выражение, связанное с ним) делает именно это.

https://www.thinktecture.com/en/entity-framework-core/making-rownumber-more-useful-in-2-1/

Но этот подход ничего не делает в EF Core 3.1

Есть ли способ создать подзапрос?

1 Ответ

1 голос
/ 04 марта 2020

Глядя на исходный код EF Core 3.1, я вижу единственный способ заставить подзапрос перед применением фильтра where - ввести ограничение запроса (т. Е. Skip и / или Take).

Из двух возможных операторов фальшивого предела (Skip(0) и Take(int.MaxValue)) похоже, что выбор последнего лучше, поскольку первый также требует некоторого упорядочения (даже фальшивого).

Таким образом, обходной путь должен быть вставлен

.Take(int.MaxValue)

до .Where(...).

Сгенерированный SQL не идеален (имеет поддельное предложение TOP), но, по крайней мере, действителен.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...