Podam podobny przykład do powyższego. Podobny, a nie taki sam bo akurat mam taką bazę danych jaką mam :)
Załóżmy, że mamy dwie tabele: Orders i Customers powiązane ze sobą kolumną CustomerID.
Mam ileś tam tysięcy rekordów w Orders i w Customers i jeśli w Orders kolumna ShipCountry == "Brazil", to w takim przypadku chcę wyświetlić ContactName z Customers.
Z użyciem LazyLoadingu kod będzie wyglądał tak:
foreach (Order order in context.Orders.OrderBy(x => x.ShipName))
{
if(order.ShipCountry == "Brazil")
Console.WriteLine("{0}, {1}, {2}", order.ShipName, order.ShipCountry, order.Customer.ContactName);
else
Console.WriteLine("{0}, {1}", order.ShipName, order.ShipCountry);
}
a do bazy danych idzie jeden prosty select na tabeli Orders plus tyle pojedynczych selectów na tabeli Customers ilu jest Customerów z Brazylii.
Bez Lazy Loadingu, kod będzie nieco bardziej skomplikowany i będzie wyglądał tak:
context.ContextOptions.LazyLoadingEnabled = false;
List<OrderCustomer> orders = (from o in context.Orders
join c in context.Customers
on o.CustomerID equals c.CustomerID
where o.ShipCountry == "Brazil"
select new OrderCustomer
{
ShipName = o.ShipName,
ShipCountry = o.ShipCountry,
ContactName = o.Customer.ContactName
})
.Union(from o in context.Orders
where o.ShipCountry != "Brazil"
select new OrderCustomer
{
ShipName = o.ShipName,
ShipCountry = o.ShipCountry,
ContactName = null
})
.OrderBy(o => o.ShipName)
.ToList();
foreach (OrderCustomer order in orders)
{
if(order.ShipCountry == "Brazil")
Console.WriteLine("{0}, {1}, {2}", order.ShipName, order.ShipCountry, order.ContactName);
else
Console.WriteLine("{0}, {1}", order.ShipName, order.ShipCountry);
}
context.ContextOptions.LazyLoadingEnabled = true;
Do bazy danych pójdzie tylko jeden select. Taki:
SELECT
[Distinct1].[C1] AS [C1],
[Distinct1].[C2] AS [C2],
[Distinct1].[C3] AS [C3],
[Distinct1].[C4] AS [C4]
FROM ( SELECT DISTINCT
[UnionAll1].[C1] AS [C1],
[UnionAll1].[ShipName] AS [C2],
[UnionAll1].[ShipCountry] AS [C3],
[UnionAll1].[ContactName] AS [C4]
FROM (SELECT
1 AS [C1],
[Extent1].[ShipName] AS [ShipName],
[Extent1].[ShipCountry] AS [ShipCountry],
[Extent2].[ContactName] AS [ContactName]
FROM [dbo].[Orders] AS [Extent1]
LEFT OUTER JOIN [dbo].[Customers] AS [Extent2] ON [Extent1].[CustomerID] = [Extent2].[CustomerID]
WHERE ([Extent1].[CustomerID] IS NOT NULL) AND (N'Brazil' = [Extent1].[ShipCountry])
UNION ALL
SELECT
1 AS [C1],
[Extent3].[ShipName] AS [ShipName],
[Extent3].[ShipCountry] AS [ShipCountry],
CAST(NULL AS varchar(1)) AS [C2]
FROM [dbo].[Orders] AS [Extent3]
WHERE N'Brazil' <> [Extent3].[ShipCountry]) AS [UnionAll1]
) AS [Distinct1]
ORDER BY [Distinct1].[C2] ASC
Wydajność kodu z Lazy Loadingiem jest uzależniona od użytkownika. Jeśli użytkownik doda Zamówienia od wielu Klientów z Brazylii, to będzie dużo pojedynczych zapytań do tabeli Customers i aplikacja będzie niewydajna. Jeśli użytkownik doda Zamówienia od niewielu Klientów z Brazylii, to będzie mało pojedynczych zapytań i aplikacja będzie w miarę szybko chodziła. Czyli w takim przypadku, należałoby w instrukcji obsługi programu napisać użytkownikowi żeby nie wstawiał Zamówień od wielu Klientów z Brazylii bo aplikacja będzie niewydajna. A jak użytkownik nie przeczyta instrukcji obsługi? Albo jeśli użytkownik będzie musiał wstawić Zamówienia od 50 tys. Customerów z Brazylii, to co wtedy? Przerabiać aplikację?
W przypadku drugiego kodu, do bazy idzie tylko jedno zapytanie i są zwracane z bazy danych tylko takie dane jakie są potrzebne. Nie ma zbędnego pobierania połowy bazy danych.
Sorry za trochę sarkastyczny ton, ale ja wciąż nie rozumiem jaki jest sens Lazy Loadingu w aplikacjach webowych?
I byłbym wdzięczny za sensowne wytłumaczenie mi tego.