EF Core 3.1 выбрать First() из Group
Есть удаленный MSSQLServer, на котором есть довольно "тяжелая" View, которую я хочу обработать на стороне сервера БД и не тащить на клиент лишние данные.
Написал запрос, который, по идее, должен вытянуть на клиент только первые значения из каждой группы по полю TAG_NAME, каждая группа в свою очередь отсортирована по дате createDate:
var tParams = context.TechSet
.Where(x => x.createDate < endDate && x.createDate > startDate)
.OrderByDescending(d => d.createDate)
.GroupBy(x=>x.TAG_NAME)
.Select(z=>z.First())
.ToList();
Получаю длинный Exception, основная суть которого следующая:
...First()' could not be translated. Either rewrite the query in a form that can be translated, or switch to client evaluation explicitly by inserting a call to either AsEnumerable(), AsAsyncEnumerable(), ToList()...
Как правильно написать запрос, чтобы он смог корректно транслироваться в SQL ?
Ответы (1 шт):
После некоторого изучения форумов пришел к выводу, что разработчики EFCore 3.0/3.1 перепроектировали LINQ провайдер и на дату задания вопроса данный фреймворк не умеет транслировать GroupBy на сторону SQL. Это весьма не очевидный факт и возможно этот оператор когда-то войдет в список транслируемых.
Также удалось найти решение, которое можно применить к моей ситуации. Основано на применении подзапроса IQueryable<T>:
var subquery = context.TechSet.Select(x => new { Key = x.TAG_NAME, Tech = x });
var parameters =
subquery.Select(x => x.Key).Distinct().SelectMany(key =>
subquery.Where(e => e.Key == key)
.Select(e => e.Tech)
.Where(t => t.createDate < endDate && t.createDate > startDate)
.OrderByDescending(m => m.createDate)
.Take(1)).ToList();
Даже при использовании подзапроса скорость выполнения выросла в 4 раза по сравнению с Where на стороне БД и (GroupBy() + First()) на стороне клиента.