Сравнение отложенной и немедленной загрузки (LINQ to SQL)
Обновлен: November 2007
При запросе объекта фактически извлекается только запрошенный объект. Связанные объекты не извлекаются автоматически одновременно с основным объектом. (Дополнительные сведения см. в разделе Выполнение запросов в связях (LINQ to SQL).) Пользователь не может определить, что связанные объекты еще не загружены, поскольку попытка получить к ним доступ приводит к выполнению запроса, который их извлекает.
Например, может возникнуть потребность выполнить запрос на получение определенного набора заказов и затем лишь при необходимости отправлять уведомления по электронной почте отдельным клиентам. В этом случае не требуется сразу извлекать все данные о клиентах вместе с каждым заказом. Можно использовать отложенную загрузку для получения дополнительной информации только тогда, когда она действительно необходима. Рассмотрим следующий пример.
Dim db As New Northwnd("c:\northwnd.mdf")
Dim notificationQuery = _
From ord In db.Orders _
Where ord.ShipVia = 3 _
Select ord
For Each ordObj As Order In notificationQuery
If ordObj.Freight > 200 Then
SendCustomerNotification(ordObj.Customer)
ProcessOrder(ordObj)
End If
Next
Northwnd db = new Northwnd(@"northwnd.mdf");
IQueryable<Order> notificationQuery =
from ord in db.Orders
where ord.ShipVia == 3
select ord;
foreach (Order ordObj in notificationQuery)
{
if (ordObj.Freight > 200)
SendCustomerNotification(ordObj.Customer);
ProcessOrder(ordObj);
}
}
Иногда бывает полезным реализовать и противоположный подход. Предположим, имеется приложение, которому требуется одновременно просматривать данные о клиентах и заказах. В этом случае необходимы оба набора данных. Поскольку приложению требуются сведения о заказах для каждого клиента в момент получения результатов, нецелесообразно отправлять отдельные запросы на получение заказов для каждого клиента. Более эффективно извлекать данные о заказах одновременно с данными о клиентах.
Dim db As New Northwnd("c:\northwnd.mdf")
db.DeferredLoadingEnabled = False
Dim custQuery = _
From cust In db.Customers _
Where cust.City = "London" _
Select cust
For Each custObj As Customer In custQuery
For Each ordObj As Order In custObj.Orders
ProcessCustomerOrder(ordObj)
Next
Next
Northwnd db = new Northwnd(@"c:\northwnd.mdf");
db.DeferredLoadingEnabled = false;
IQueryable<Customer> custQuery =
from cust in db.Customers
where cust.City == "London"
select cust;
foreach (Customer custObj in custQuery)
{
foreach (Order ordObj in custObj.Orders)
{
ProcessCustomerOrder(ordObj);
}
}
Можно также объединить клиентов и заказы в одном запросе путем создания перекрестного произведения и извлечения всех связанных битов данных в виде одной большой проекции. Однако эти результаты не являются сущностями (дополнительные сведения см. в разделе Модель объектов LINQ to SQL). Сущности представляют собой объекты, которые обладают идентификациями и которые можно изменить. Результаты, напротив, являются проекциями, и их нельзя ни изменить, ни сохранить. Более того, при таком подходе извлекается большое количество избыточных данных, поскольку в плоских выходных данных, полученных в результате объединения, каждый клиент повторяется в каждом заказе.
Действительно эффективным стал бы способ параллельного извлечения набора связанных объектов. Этот набор является отделенным разделом графа, поэтому пользователь извлекает ровно тот объем данных, который ему необходим. Для этой цели в LINQ to SQL предусмотрены параметры DataLoadOptions, позволяющие немедленно загружать область объектной модели. Ниже перечислены используемые методы.
Метод LoadWith для немедленной загрузки данные, связанных с основными целевыми объектами.
Метод AssociateWith для фильтрации объектов, извлеченных для определенной связи.