Entity Framework jest jedną z platform ORM, która pozwala na współpracę pomiędzy bazą danych a obiektowym językiem programowania. Dane które są pobierane za pośrednictwem EF są podzielone na dwa tryby: lazy loading lub eager loading.
Lazy loading (leniwe ładowanie) polega na każdorazowym odpytywaniu bazę danych o interesujące nas informacje (jeśli property nawigacyjne jest NULL). Jest domyślnym trybem w Entity.
Aby bardziej przybliżyć pojęcie “leniwego ładowania” najlepiej będzie jeżeli zobrazujemy go na przykładzie.
Baza danych składa się z dwóch tabel. Jedna zawiera informacje o nazwie drużyny piłkarskiej
natomiast druga o zawodnikach przypisanych do w/w zespołu. Zauważmy, że jest to relacja jeden do wielu tj. jeden zawodnik może być przypisany tylko do jednej drużyny lecz jedna drużyna może mieć wielu zawodników.
Implementacja pobierania danych jest dość prosta. W pierwszej kolejności pobieramy tabele z zawodnikami a następnie pętlą wyświetlamy informacje na temat imienia, nazwiska piłkarza oraz drużyny w której gra. Trzecia linijka w kodzie służy do wyświetlania loga który jest połączony z naszą bazą danych.
using (testEntities test = new testEntities()) { test.Database.Log = Console.WriteLine; var lazyLoading = test.zawodnicies; foreach (var item in lazyLoading) { Console.WriteLine(item.Imie + " " + item.Nazwisko + " gra dla " + item.druzyny.NazwaDruzyny + " z ligi " + item.druzyny.Liga); } Console.ReadLine(); }
Po uruchomieniu programu widzimy, że nasze “leniwe ładowanie” wygenerowało trzy zapytania do naszej bazy danych. Przy tak małej ilości powiązań i rekordów jest to praktycznie niezauważalne ale przy większej ilości danych powstaje problem N+1.
Eager loading (chciwe ładowanie) ogranicza zapytania do bazy kosztem pobrania i przechowywania wszystkich danych z konkretnych tabel w pamięci. Najlepiej będzie, jeśli zobrazujemy to na przykładzie z zawodnikami i drużynami.
Istotną rzeczą jest użycie słowa kluczowego “Include” które mówi Entity że teraz chcemy używać eager loading. Kod jest analogiczny w porówaniu z lazy loading poza 4 linijką kodu gdzie pobieramy wszystkie dane z tabeli: zawodnicy i drużyny.
using (testEntities test = new testEntities()) { test.Database.Log = Console.WriteLine; var eagerloading = test.zawodnicies.Include(x => x.druzyny); foreach (var item in eagerloading) { Console.WriteLine(item.Imie + " " + item.Nazwisko + " gra dla " + item.druzyny.NazwaDruzyny + " z ligi " + item.druzyny.Liga); } Console.ReadLine(); }
Możemy również w ramach IQueryable zrobić “selecta” – wtedy nie musimy dodawać “Include” ponieważ materializujemy zapytanie do postaci “listy”.
var result = context.Zawodnicy.Select(z => new { Imie = z.Imie, Nazwisko = z.Nazwisko, NazwaDruzyny = z.druzyny.NazwaDruzyny }).ToList();
Po uruchomieniu programu widzimy, że wygenerowaliśmy tylko jedno zapytanie do bazy, a otrzymaliśmy te same informacje jak w trybie lazy loading.
Podsumowanie:
Kiedy używać Lazy loading a kiedy Eager loading.
Lepszym zastosowaniem dla użycia lazy loading jest wariant, gdy chcemy pozyskać jakieś pojedyncze informacje z jednej tabeli (np.gdy potrzebujemy tylko imiona i nazwiska piłkarzy a nie potrzebujemy pobierać informacji o drużynach i zaśmiecać sobie nimi pamięci).
Gdy potrzebujemy wszystkie informacje z relacyjnych tabel (np. drużyn i zawodników) wtedy najlepszym i najszybszym sposobem pozyskania danych będzie zastosowanie eager loading.
Świetne wyjaśnienie różnic pomiędzy tymi dwoma sposobami ładowania. Są to wszystkie różnice, czy o jakichś jeszcze nie wspomniałeś?
I wrote an article with programming views on Lazy Loading vs Eager Loading,
http://www.codedjava.com/2017/09/eager-loading-vs-lazy-loading.html
Thanks.