Таким образом, я пытаюсь понять IQueryable<T>
. Учебное руководство, которое я читаю, предлагает использовать его, но не действительно уверенное почему. Код просто возвращает некоторые значения с помощью LINQ для SQL. Я сделал это много времен в прошлом, но не использования IQueryable<T>
Почему использование это с моими функциями, которые возвращают больше чем 1 значение?
Вот мой код:
public IQueryable<Items> GetItems()
{
return from item in db.Items
where item.IsActive == true
orderby item.ItemNumber
select item;
}
IQueryable представляет запрос в виде дерева выражений, не оценивая его на сервере. Это позволяет задать дальнейшую обработку перед тем, как генерировать SQL.
В приведенном выше случае это означает, что вы можете делать разные вещи с результатом вызова GetItems(), и исходный запрос и дополнительные вещи будут отправлены как один запрос:
var recentItems = from item in GetItems()
where item.Timestamp > somedate
select item;
foreach (var item in recentItems)
{
// Do something with an active recent item.
}
Ничего не отправляется на сервер, пока мы не попытаемся использовать результат в цикле foreach. В этот момент провайдер LINQ-to-SQL оценивает все выражение, включая части, сгенерированные внутри GetItems()
, и части, указанные после, и выдает один SQL-запрос, который выбирает все элементы, которые являются активными и недавними.
Чтобы прояснить один технический момент, IQueryable
является IEnumerable
, и его поставщик вычисляет окончательный SQL, когда вы пытаетесь вызвать метод GetEnumerator()
на нем. Вы можете сделать это либо явно, вызвав его, либо неявно, используя его в операторе foreach
. Кроме того, такие методы расширения, как ToArray()
, выполняют один из этих методов внутри, что дает тот же эффект.
IQueryable (до перечисления) - это не сами результаты, а логика, используемая для возврата этих результатов.
Для примера LINQ2SQL... представьте, что вы возвращаете IQueryable of Clients. Под капотом это будет не список клиентов (пока вы не перечислите их в ToList()), а SQL-запрос следующего вида:
SELECT * FROM [Clients]
Это удобно, потому что мы еще не обратились к базе данных! Итак, допустим, когда IQueriable вернется, мы хотим уточнить его до клиентов по имени "Боб", мы можем сделать следующее:
var clients = GetClients().Where(c => c.Name == "Bob");
Теперь IQueriable выглядит следующим образом:
SELECT * FROM [Clients] WHERE Name = 'Bob'.
Теперь, когда я делаю clients.ToList(), этот запрос будет выполнен, база данных обращена, и у меня есть список клиентов по имени bob без необходимости выбирать всех клиентов, затем перебирать их в памяти или выполнять 2 отдельных обращения к базе данных.
В качестве примера того, как это может аукнуться, попробуйте добраться до дочерних элементов, когда ваш datacontext вышел из области видимости (например, запустите select внутри оператора using). Вот где пригодятся опции загрузки в LINQ2SQL.
Надеюсь, это поможет
.