Какая польза IQueryable
в контексте LINQ?
Используется ли он для разработки методов расширения или для каких-либо других целей?
источник
Какая польза IQueryable
в контексте LINQ?
Используется ли он для разработки методов расширения или для каких-либо других целей?
Ответ Марка Гравелла очень полный, но я решил добавить кое-что об этом и с точки зрения пользователя ...
Основное отличие, с точки зрения пользователя, заключается в том, что при использовании IQueryable<T>
(с поставщиком, который поддерживает все правильно) вы можете сэкономить много ресурсов.
Например, если вы работаете с удаленной базой данных во многих системах ORM, у вас есть возможность извлекать данные из таблицы двумя способами: один возвращает IEnumerable<T>
, а другой возвращает IQueryable<T>
. Например, у вас есть таблица «Продукты», и вы хотите получить все продукты, стоимость которых> 25 долларов США.
Если вы делаете:
IEnumerable<Product> products = myORM.GetProducts();
var productsOver25 = products.Where(p => p.Cost >= 25.00);
Здесь происходит то, что база данных загружает все продукты и передает их по проводам в вашу программу. Ваша программа затем фильтрует данные. По сути, база данных делает SELECT * FROM Products
и возвращает вам КАЖДЫЙ продукт.
С подходящим IQueryable<T>
поставщиком, с другой стороны, вы можете сделать:
IQueryable<Product> products = myORM.GetQueryableProducts();
var productsOver25 = products.Where(p => p.Cost >= 25.00);
Код выглядит так же, но разница здесь в том, что выполненный SQL будет SELECT * FROM Products WHERE Cost >= 25
.
С вашей точки зрения, как разработчика, это выглядит так же. Однако с точки зрения производительности вы можете вернуть только 2 записи по сети вместо 20 000 ...
IQueryable<Product>
- будет специфичным для вашего ORM или репозитория и т. Д.foreach
или вызовитеToList()
), вы фактически не попадете в БД.По сути, его работа очень похожа на
IEnumerable<T>
представление запрашиваемого источника данных. Разница заключается в том, что различные методы LINQ (onQueryable
) могут быть более конкретными: создавать запрос с использованиемExpression
деревьев, а не делегатов (что иEnumerable
используется).Деревья выражений могут быть проверены выбранным вами поставщиком LINQ и превращены в реальный запрос - хотя это само по себе чёрное искусство.
Это действительно до
ElementType
,Expression
иProvider
- но на самом деле вам редко нужно заботиться об этом как о пользователе . Только исполнитель LINQ должен знать мрачные детали.Повторные комментарии; Я не совсем уверен, что вы хотите в качестве примера, но рассмотрим LINQ-to-SQL; Центральный объект здесь представляет собой
DataContext
, который представляет нашу обертку базы данных. Это обычно имеет свойство для таблицы (например,Customers
), и таблица реализуетIQueryable<Customer>
. Но мы не используем так много напрямую; рассматривать:это делается (компилятором C #):
который снова интерпретируется (компилятором C #) как:
Важно отметить, что статические методы
Queryable
принимают деревья выражений, которые, вместо обычного IL, компилируются в объектную модель. Например - просто глядя на «Где», это дает нам нечто сравнимое с:Разве компилятор не сделал для нас много? Эту объектную модель можно разорвать на части, проверить, что это значит, и снова собрать вместе с помощью генератора TSQL - что-то вроде:
(строка может оказаться в качестве параметра; я не могу вспомнить)
Ничего из этого не было бы возможным, если бы мы только что использовали делегата. И это точка
Queryable
/IQueryable<T>
: она обеспечивает точку входа для использования деревьев выражений.Все это очень сложно, поэтому хорошо, что компилятор делает это легко и просто для нас.
Для получения дополнительной информации посмотрите « C # in Depth » или « LINQ в действии », которые оба охватывают эти темы.
источник
Хотя Рид Копси и Марк Гравелл уже достаточно подробно описали
IQueryable
(а такжеIEnumerable
), я хочу добавить немного больше, приведя небольшой пример,IQueryable
иIEnumerable
столько пользователей просили об этом.Пример : я создал две таблицы в базе данных
Первичный ключ (
PersonId
) таблицыEmployee
также является поддельным ключом (personid
) таблицыPerson
Затем я добавил модель сущности ado.net в свое приложение и создал ниже класс обслуживания на этом
они содержат одно и то же linq. Это называется
program.cs
как определено нижеВывод одинаков для обоих, очевидно,
Итак, вопрос в том, в чем / где разница? Кажется, нет никакой разницы, верно? В самом деле!!
Давайте посмотрим на sql запросы, сгенерированные и выполненные примитивами framwork 5 за этот период.
IQueryable исполнительная часть
IEnumerable часть исполнения
Общий сценарий для обеих исполнительных частей
Итак, у вас есть несколько вопросов, позвольте мне угадать их и попытаться ответить на них.
Почему разные сценарии генерируются для одного и того же результата?
Давайте выясним некоторые моменты здесь,
все запросы имеют одну общую часть
WHERE [Extent1].[PersonId] IN (0,1,2,3)
Зачем? Потому что как функция, так
IQueryable<Employee> GetEmployeeAndPersonDetailIQueryable
иIEnumerable<Employee> GetEmployeeAndPersonDetailIEnumerable
ofSomeServiceClass
содержит одну общую строку в запросах linqwhere employeesToCollect.Contains(e.PersonId)
Почему
AND (N'M' = [Extent1].[Gender])
часть отсутствует вIEnumerable
части исполнения, а при вызове обеих функций мы использовалиWhere(i => i.Gender == "M") in
program.cs`Что делает фреймворк для сущностей при
IQueryable
вызове метода, он обрабатывает оператор linq, написанный внутри метода, и пытается выяснить, определено ли больше выражений linq в результирующем наборе, затем он собирает все определенные запросы linq до тех пор, пока результат не должен быть извлечен, и не создает более подходящий sql запрос для выполнения.Это обеспечивает много преимуществ, таких как,
как здесь, в примере, сервер sql вернул приложению только две строки после выполнения IQueryable`, но возвратил ТРИ строки для запроса IEnumerable, почему?
В случае
IEnumerable
метода, структура сущности взяла оператор linq, написанный внутри метода, и создает запрос sql, когда нужно получить результат. он не включает в себя rest linq part для создания запроса sql. Как и здесь, в столбце sql server не выполняется фильтрацияgender
.Но выходы такие же? Потому что 'IEnumerable фильтрует результат дальше на уровне приложения после получения результата от сервера SQL
Итак, что выбрать? Лично я предпочитаю определять результат функции,
IQueryable<T>
потому что есть много преимуществ, которые он имеет,IEnumerable
например, вы можете объединить две или более функций IQueryable, которые генерируют более специфический скрипт для сервера sql.Здесь в примере вы можете увидеть, что
IQueryable Query(IQueryableQuery2)
генерирует более конкретный сценарий, чем тот,IEnumerable query(IEnumerableQuery2)
который на мой взгляд более приемлем.источник
Это позволяет для дальнейшего запроса дальше вниз по линии. Если бы это было, скажем, за пределами сервисной границы, то пользователю этого объекта IQueryable было бы разрешено делать с ним больше.
Например, если вы используете ленивую загрузку с помощью nhibernate, это может привести к загрузке графика, когда / при необходимости.
источник