Я знаю некоторые отличия LINQ to Entities и LINQ to Objects, которые реализует первый, IQueryable
а второй реализует, IEnumerable
и мой вопрос находится в EF 5.
Мой вопрос: в чем техническая разница (и) этих 3 методов? Я вижу, что во многих ситуациях все они работают. Я также вижу, как использовать их комбинации .ToList().AsQueryable()
.
Что конкретно означают эти методы?
Есть ли проблемы с производительностью или что-то, что может привести к использованию одного над другим?
Почему бы, например, использовать
.ToList().AsQueryable()
вместо.AsQueryable()
?
Ответы:
Об этом можно многое сказать. Позвольте мне сосредоточиться на
AsEnumerable
иAsQueryable
и УпоминаниеToList()
по пути.Что делают эти методы?
AsEnumerable
иAsQueryable
приведение или преобразование вIEnumerable
илиIQueryable
, соответственно. Я говорю приведение или преобразование с причиной:Когда исходный объект уже реализует целевой интерфейс, сам исходный объект возвращается , но брошен на целевой интерфейс. Другими словами: тип не изменяется, но тип времени компиляции.
Когда исходный объект не реализует целевой интерфейс, исходный объект преобразуется в объект, который реализует целевой интерфейс. Таким образом, тип и тип времени компиляции изменены.
Позвольте мне показать это на нескольких примерах. У меня есть этот маленький метод, который сообщает тип времени компиляции и фактический тип объекта ( любезно предоставлено Jon Skeet ):
Давайте попробуем произвольный linq-to-sql
Table<T>
, который реализуетIQueryable
:Результат:
Вы видите, что сам класс таблицы всегда возвращается, но его представление изменяется.
Теперь объект, который реализует
IEnumerable
, а неIQueryable
:Результаты:
Вот оно
AsQueryable()
преобразовал массив в объектEnumerableQuery
, который «представляетIEnumerable<T>
коллекцию в качествеIQueryable<T>
источника данных». (MSDN).Какая польза?
AsEnumerable
часто используется для переключения с любойIQueryable
реализации на LINQ на объекты (L2O), главным образом потому, что первая не поддерживает функции, которые есть в L2O. Для получения дополнительной информации см. Как влияет AsEnumerable () на объект LINQ? ,Например, в запросе Entity Framework мы можем использовать только ограниченное количество методов. Так что, если, например, нам нужно использовать один из наших собственных методов в запросе, мы обычно пишем что-то вроде
ToList
- который преобразуетIEnumerable<T>
вList<T>
- часто используется для этой цели. Преимущество использованияAsEnumerable
vs.ToList
заключается в томAsEnumerable
, что запрос не выполняется.AsEnumerable
сохраняет отложенное выполнение и не создает часто бесполезный промежуточный список.С другой стороны, когда требуется принудительное выполнение запроса LINQ,
ToList
может быть способ сделать это.AsQueryable
может использоваться для того, чтобы перечисляемая коллекция принимала выражения в операторах LINQ. Смотрите здесь для более подробной информации: действительно ли мне нужно использовать AsQueryable () для коллекции? ,Обратите внимание на токсикоманию!
AsEnumerable
работает как наркотик. Это быстрое решение, но оно стоит денег и не решает основную проблему.Во многих ответах на переполнение стека я вижу людей, обращающихся
AsEnumerable
за исправлением практически любой проблемы с неподдерживаемыми методами в выражениях LINQ. Но цена не всегда ясна. Например, если вы делаете это:... все аккуратно переведено в оператор SQL, который filters (
Where
) и projects (Select
). Таким образом, длина и ширина соответственно результирующего набора SQL сокращаются.Теперь предположим, что пользователи хотят видеть только часть даты
CreateDate
. В Entity Framework вы быстро обнаружите, что ...... не поддерживается (на момент написания статьи). Ах, к счастью, есть
AsEnumerable
исправление:Конечно, это работает, наверное. Но он вытягивает всю таблицу в память, а затем применяет фильтр и проекции. Ну, большинство людей достаточно умны, чтобы сделать
Where
первое:Но все же все столбцы извлекаются первыми, и проекция выполняется в памяти.
Настоящее исправление:
(Но это требует немного больше знаний ...)
Что эти методы НЕ делают?
Восстановить IQueryable возможности
Теперь важное предостережение. Когда вы делаете
Вы получите исходный объект, представленный как
IQueryable
. (Потому что оба метода только приводят и не конвертируют).Но когда вы делаете
какой будет результат?
Select
ПроизводитWhereSelectEnumerableIterator
. Это внутренний класс .Net, который реализуетIEnumerable
, а неIQueryable
. Таким образом, произошло преобразование в другой тип, и последующееAsQueryable
больше не сможет вернуть исходный источник.Смысл этого в том, что использование
AsQueryable
- это не способ волшебным образом внедрить поставщика запросов с его специфическими функциями в перечисляемый. Предположим, вы делаетеУсловие where никогда не будет переведено в SQL.
AsEnumerable()
затем операторы LINQ окончательно разрывают соединение с провайдером запросов платформы сущностей.Я намеренно показываю этот пример, потому что я видел здесь вопросы, когда люди, например, пытаются «внедрить»
Include
возможности в коллекцию путем вызоваAsQueryable
. Он компилируется и запускается, но ничего не делает, потому что базовый объект больше не имеетInclude
реализации.казнить
Оба
AsQueryable
иAsEnumerable
не выполняют (или перечисляют ) исходный объект. Они только меняют свой тип или представление. Оба задействованных интерфейса,IQueryable
иIEnumerable
, являются ничем иным, как «перечислением, ожидающим произойти». Они не выполняются до того, как их заставляют, например, как упоминалось выше, путем вызоваToList()
.Это означает , что выполнение
IEnumerable
получить, позвонивAsEnumerable
наIQueryable
объект, будет выполнять лежащий в основеIQueryable
. Последующее выполнениеIEnumerable
снова будет выполнятьIQueryable
. Который может быть очень дорогим.Конкретные реализации
Пока что речь шла только о методах расширения
Queryable.AsQueryable
иEnumerable.AsEnumerable
. Но, конечно, любой может написать методы экземпляра или методы расширения с одинаковыми именами (и функциями).На самом деле, типичным примером конкретного
AsEnumerable
метода расширения являетсяDataTableExtensions.AsEnumerable
.DataTable
не реализуетIQueryable
илиIEnumerable
, поэтому обычные методы расширения не применяются.источник
AsQueryable()
часто основано на заблуждении. Но я позволю себе немного расслабиться и посмотрим, смогу ли я добавить больше освещения по этому вопросу.К списку()
AsEnumerable ()
Func<TSource, bool>
AsQueryable ()
Expression<Func<TSource, bool>>
AsQueryable()
обычно работает намного быстрее, чемAsEnumerable()
при генерации T-SQL, что включает все ваши условия where в вашем Linq.источник
ToList () будет всем в памяти, а затем вы будете работать над этим. Итак, ToList (). где (применить некоторый фильтр) выполняется локально. AsQueryable () выполнит все удаленно, т.е. фильтр по нему будет отправлен в базу данных для применения. Queryable ничего не делает, пока вы не выполните его. ToList, однако, выполняется немедленно.
Кроме того, посмотрите на этот ответ. Зачем использовать AsQueryable () вместо List ()? ,
РЕДАКТИРОВАТЬ: Кроме того, в вашем случае, когда вы делаете ToList (), то каждая последующая операция является локальной, включая AsQueryable (). Вы не можете переключиться на удаленный, когда вы начнете выполнять локально. Надеюсь, что это делает это немного яснее.
источник
Обнаружена плохая производительность в приведенном ниже коде.
Исправлено с
Для IQueryable оставайтесь в IQueryable, когда это возможно, старайтесь не использовать его как IEnumerable.
Обновление . Это можно еще больше упростить в одном выражении, спасибо Герту Арнольду .
источник