Вложенный выбор Linq EF Core приводит к N + 1 SQL-запросамC#

Место общения программистов C#
Anonymous
Вложенный выбор Linq EF Core приводит к N + 1 SQL-запросам

Сообщение Anonymous »

У меня есть модель данных, в которой объект «Верхний» имеет от 0 до N объектов «Подчиненный». В SQL это достигается с помощью внешнего ключа dbo.Sub.TopId.

Код: Выделить всё

var query = context.Top
//.Include(t => t.Sub) Doesn't seem to do anything
.Select(t => new {
prop1 = t.C1,
prop2 = t.Sub.Select(s => new {
prop21 = s.C3 //C3 is a column in the table 'Sub'
})
//.ToArray() results in N + 1 queries
});
var res = query.ToArray();
В Entity Framework 6 (с отключенной отложенной загрузкой) этот запрос Linq будет преобразован в один запрос SQL. Результат будет полностью загружен, поэтому res[0].prop2 будет IEnumerable, который уже заполнен.

Однако при использовании EntityFrameworkCore (NuGet v1.1.0) подколлекция еще не загружена и имеет тип:

Код: Выделить всё

System.Linq.Enumerable.WhereSelectEnumerableIterator.
Данные не будут загружены, пока вы не выполните итерацию по ним, что приведет к N + 1 запросам. Когда я добавляю .ToArray() к запросу (как показано в комментариях), данные полностью загружаются в var res, однако использование профилировщика SQL показывает, что этого больше не достигается в одном SQL-запросе. Для каждого объекта «Top» выполняется запрос к таблице «Sub».

Первое указание .Include(t => t.Sub), похоже, ничего не меняет. Использование анонимных типов также не является проблемой: замена новых блоков { ... на новые MyPocoClass { ... ничего не меняет.

Мой вопрос: Есть ли способ добиться поведения, аналогичного EF6, где все данные загружаются немедленно?



Примечание: я понимаю: что в этом примере проблему можно решить, создав анонимные объекты в памяти после выполнения запроса следующим образом:

Код: Выделить всё

var query2 = context.Top
.Include(t => t.Sub)
.ToArray()
.Select(t => new //... select what is needed, fill anonymous types
Однако это всего лишь пример, мне действительно нужно, чтобы создание объектов было частью запроса Linq, поскольку AutoMapper использует это для заполнения DTO в моем проекте.




Обновление: Протестировано с новым EF Core 2.0, проблема все еще присутствует. (21-08-2017)

Проблема отслеживается в aspnet/EntityFrameworkCore Репозиторий GitHub: Проблема 4007



Обновление: Год спустя эта проблема была исправлена в версии 2.1.0-preview1-final. (01.03.2018)


Обновление: Выпущена версия EF 2.1 с исправлением. см. мой ответ ниже. (31 мая 2018 г.)

Вернуться в «C#»