Linq возвращает IEnumerable вместо IQueryable

175
17 марта 2018, 14:58

Заметил что Linq в .net core 2.0 возвращает IEnumerable, вместо привычного IQueryable, работать с EF можно, но если в БД будет 2 миллиона записей и они выгрузятся в память будет - плохо. В решения только нашёл подключить: System.Linq.Queryable. Но это не помогает, так как я не нашёл способа выкосить старый Linq.

Answer 1

Полного кода метода нет, так что ответ наугад:

IQueryable<TEntity> = dbSet.Where(predicate);

Скорее всего predicate объявлен как

Func<TEntity, bool> predicate = ...

Дело в том, что метод Queryable.Where принимает не Func<TEntity, bool>, а Expression<Func<TEntity, bool>>.

А вот метод Enumerable.Where принимает просто Func<TEntity, bool>.

Func<TEntity, bool> - это просто делегат, который принимает TEntity и возвращает bool. Внутри делегата может быть любой метод с подходящей сигнатурой.

Если вы напишете

Func<TEntity, bool> predicate = e => e.Id > 5;

то компилятор просто создаст метод вида

bool someMethod(TEntity e)
{
    return e.Id > 5;
}

Этот делегат можно вызывать, но вот залезть внутрь делегата, достать оттуда содержимое метода и как-то его превратить в SQL не получится. Поэтому делегата достаточно для Enumerable, но не для Queryable.

Expression<Func<TEntity, bool>> - это объект, а не метод.

Если вы напишете в коде

Expression<Func<TEntity, bool>> predicate = e => e.Id > 5;

то компилятор развернет это примерно в

Expression<Func<TEntity, bool>> predicate = Expression.Lambda(
                Expression.MakeBinary(
                     ExpressionType.Equal,
                     Expression.PropertyAccess("e", "Id"),
                     Expresison.Const("5")....

и вот такое дерево объектов LINQ-провайдер легко может разобрать и превратить в соответствующий код SQL.

Обычно в коде для работы с LINQ используют лямбды. Лямбды компилируются или в анонимные методы, или в деревья выражений, в зависимости от контекста. При этом дерево выражений считается предпочтительным вариантом. Т.е. если вы напишете

dbSet.Where(e => e.Id == 5);

то компилятор предпочтет перегрузку с Expression и, соответственно, механизм IQueryable. Но т.к. вы явно задали тип предиката как Func - вы принудительно выбрали IEnumerable.

Поменяйте тип у predicate на Expression<> и все будет ок.

Answer 2

Если использовать фильтрацию по Where, она будет выполнена на серверной стороне, и ничего лишнего выгружено не будет.

using (var context = new BloggingContext())
{
    var blogs = context.Blogs
    .Where(b => b.Url.Contains("dotnet"))
    .ToList();
}

Этот код сгенерирует SQL с условием WHERE blogs.Url LIKE '%dotnet%' и выполнит его на стороне бд в момент перечисления массива. В приведённом коде это произойдёт в момент вызова .ToList();

Почитайте документацию

READ ALSO
Решить пример записав его условие не используя массивы

Решить пример записав его условие не используя массивы

В начале пытался записать через for( int i = 1; i==256; i*2){} Но что-то пошло не так и я не смог понять,как делить до определенного делителя, не используя...

196
Где хранить временные файлы?

Где хранить временные файлы?

Нужна временная папка для хранения и обработки файловПрочитал на msdn, что можно воспользоваться Path

188
Где ошибка в кастомной реализации MD5?

Где ошибка в кастомной реализации MD5?

Дана кастомная реализация MD5, найденная на просторах сети

146