У меня есть модель данных, в которой объект 'Top' имеет объекты от 0 до N 'Sub'. В SQL это достигается с помощью внешнего ключа dbo.Sub.TopId
.EF Core вложен Linq выбрать результаты в N + 1 SQL-запросы
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<SomeAnonymousType>
, который уже заполнен.
При использовании EntityFrameworkCore (NuGet v1.1.0), однако суб-коллекции еще не загружен и имеет тип:
System.Linq.Enumerable.WhereSelectEnumerableIterator<Microsoft.EntityFrameworkCore.Storage.ValueBuffer, <>f__AnonymousType1<string>>.
Данные не будут загружены, пока вы не итерацию над ним, в результате чего N + 1 запрос. Когда я добавляю .ToArray()
к запросу (как показано в комментариях), данные полностью загружаются в var res
, используя профилировщик SQL, однако показывает, что это больше не выполняется в 1 запросе SQL. Для каждого объекта «Top» выполняется запрос в таблице «Sub».
Сперва указавший .Include(t => t.Sub)
, кажется, ничего не изменит. Использование анонимных типов тоже не является проблемой, заменив блоки new { ... }
на new 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 репо: Issue 4007
Update: Через год эта проблема была исправлена в версии 2.1.0-preview1-final
см мой ответ ниже. (01-03-2018)
Можете ли вы показать нам, где/как вы поворачиваете ленивый груз? –
Лёгкая нагрузка применяется к EF6. Мой вопрос касается EF Core. Насколько я знаю, Core не имеет ленивой загрузки. – GWigWam
А, okidoke ... включение, которое вы используете для попытки выполнения. Нежелательная загрузка игнорируется, потому что вы не возвращаете экземпляр объекта типа, с которого начинается запрос. –