C# Academy · Lekcja

Ładowanie eager, lazy i explicit

Kontroluj moment ładowania powiązanych danych za pomocą Include, ThenInclude, proxy lazy loading i wywołań Load.

Lekcja 1 z 413 kroki

Ładowanie eager, lazy i explicit to bezpłatna lekcja C# Academy na CoddyKit. To lekcja 1 z 4. Możesz przeczytać całą lekcję poniżej za darmo — a potem ćwiczyć ją interaktywnie w przeglądarce z wbudowanym edytorem kodu i tutorem AI dostępnym 24/7. To część ścieżki edukacyjnej C# Academy, a Twój postęp synchronizuje się między webem a aplikacją CoddyKit. Kurs C# Academy zawiera 4 lekcji w sumie.

Trzy strategie ładowania

EF Core oferuje trzy strategie ładowania powiązanych danych: Eager Loading (ładowanie wraz z zapytaniem), Lazy Loading (ładowanie przy uzyskaniu dostępu) i Explicit Loading (ładowanie na żądanie). Wybór właściwej strategii pozwala uniknąć problemu N+1 i niepotrzebnych odwołań do bazy danych.

Eager Loading z Include

Eager loading używa Include(), aby dołączyć powiązane dane w ramach tego samego zapytania SQL. Jest to najbardziej przewidywalna strategia i pozwala uniknąć problemów N+1.

// Single query with JOIN
var blogs = await _db.Blogs
    .Include(b => b.Posts)
    .Where(b => b.IsActive)
    .ToListAsync();

// SQL: SELECT * FROM Blogs LEFT JOIN Posts ON ...

ThenInclude dla zagnieżdżonych relacji

ThenInclude pozwala przejść głębiej w grafie nawigacji. W ramach jednego zapytania można załadować wiele poziomów.

var orders = await _db.Orders
    .Include(o => o.Customer)
    .Include(o => o.Lines)
        .ThenInclude(l => l.Product)
            .ThenInclude(p => p.Category)
    .Where(o => o.Status == OrderStatus.Pending)
    .ToListAsync();

Filtrowanie w Include

EF Core 5+ obsługuje filtrowanie powiązanych danych wewnątrz Include. Dzięki temu można załadować podzbiór encji podrzędnych bez wykonywania osobnego zapytania.

// Load only published posts for each blog
var blogs = await _db.Blogs
    .Include(b => b.Posts.Where(p => p.IsPublished)
                         .OrderByDescending(p => p.PublishedAt)
                         .Take(5))
    .ToListAsync();

Konfigurowanie Lazy Loading

Lazy loading automatycznie ładuje właściwości nawigacyjne przy pierwszym uzyskaniu do nich dostępu. Należy go włączyć, instalując pakiet Microsoft.EntityFrameworkCore.Proxies i wywołując UseLazyLoadingProxies().

// 1. Install package: dotnet add package Microsoft.EntityFrameworkCore.Proxies
// 2. Enable in DbContext setup:
builder.Services.AddDbContext<AppDbContext>(opt =>
    opt.UseSqlite(connStr)
       .UseLazyLoadingProxies());

// 3. Mark navigation properties as virtual:
public class Blog
{
    public int Id { get; set; }
    public virtual ICollection<Post> Posts { get; set; } = new List<Post>();
}

Lazy Loading w praktyce (i pułapka N+1)

Lazy loading jest wygodny, ale niebezpieczny w pętlach — każdy dostęp uruchamia nowe zapytanie SQL, powodując problem N+1. W scenariuszach obejmujących listy należy zawsze preferować eager loading.

var blogs = await _db.Blogs.ToListAsync(); // 1 query

foreach (var blog in blogs)
{
    // BAD: each access fires a new query!
    var count = blog.Posts.Count; // N queries
    Console.WriteLine(count);
}

// FIX: Use eager loading
var blogs2 = await _db.Blogs.Include(b => b.Posts).ToListAsync();

Explicit Loading

Explicit loading pozwala ładować właściwość nawigacyjną na żądanie za pomocą Entry().Collection().LoadAsync() lub Entry().Reference().LoadAsync(). Jest to przydatne, gdy powiązane dane są potrzebne tylko warunkowo.

var blog = await _db.Blogs.FindAsync(1); // no posts loaded

// Load posts only when needed
if (needsPosts)
{
    await _db.Entry(blog!)
             .Collection(b => b.Posts)
             .LoadAsync();
}

// Load single reference
var post = await _db.Posts.FindAsync(99);
await _db.Entry(post!)
         .Reference(p => p.Blog)
         .LoadAsync();

Explicit Loading z filtrem zapytania

Jawne ładowanie można filtrować za pomocą .Query() przed wywołaniem LoadAsync(), ograniczając ilość zwracanych danych.

var blog = await _db.Blogs.FindAsync(1);

// Only load posts published this year
await _db.Entry(blog!)
         .Collection(b => b.Posts)
         .Query()
         .Where(p => p.PublishedAt.Year == DateTime.UtcNow.Year)
         .LoadAsync();

Console.WriteLine(blog!.Posts.Count);

Zapytania dzielone dla dużych operacji Include

Ładowanie wielu kolekcji w jednym zapytaniu powoduje eksplozję kartezjańską (mnożenie liczby wierszy). Należy użyć AsSplitQuery(), aby wykonać osobne zapytania dla każdej kolekcji, a następnie połączyć wyniki w pamięci.

var orders = await _db.Orders
    .Include(o => o.Lines)
    .Include(o => o.Shipments)
    .AsSplitQuery()  // 3 separate SELECTs instead of one giant JOIN
    .ToListAsync();

// Or configure globally:
opt.UseQuerySplittingBehavior(QuerySplittingBehavior.SplitQuery);

Projekcja zapobiegająca pobieraniu nadmiarowych danych

Zamiast ładować pełne encje wraz ze wszystkimi powiązaniami, należy użyć Select, aby utworzyć projekcję do obiektu DTO. Dzięki temu w jednym zoptymalizowanym zapytaniu zostaną pobrane dokładnie potrzebne dane.

var summaries = await _db.Blogs
    .Select(b => new BlogSummaryDto
    {
        Name      = b.Name,
        PostCount = b.Posts.Count(p => p.IsPublished),
        LatestPost = b.Posts
            .Where(p => p.IsPublished)
            .OrderByDescending(p => p.PublishedAt)
            .Select(p => p.Title)
            .FirstOrDefault()
    })
    .ToListAsync();
// No Include needed - translated to subqueries

Praktyka: wybór właściwej strategii

W praktyce należy korzystać z następującego przewodnika decyzyjnego:

  • Eager + Include: gdy powiązane dane są zawsze potrzebne, na przykład na stronach list
  • Projection: widoki tylko do odczytu i odpowiedzi API — najbardziej wydajne rozwiązanie
  • Explicit: warunkowe ładowanie zależne od logiki aplikacji
  • Lazy: należy unikać w aplikacjach internetowych; używać tylko w aplikacjach desktopowych lub skryptach z małymi zbiorami danych

Szybkie sprawdzenie

Czym jest problem N+1 w kontekście lazy loading?

Podsumowanie: strategie ładowania

Najważniejsze informacje:

  • Eager loading (Include): ładuje dane w jednym zapytaniu — najlepsze rozwiązanie przy przewidywalnych sposobach dostępu do danych
  • Filtered Include: ładuje tylko podzbiór elementów podrzędnych — EF Core 5+
  • Lazy loading: wygodne, ale ryzykowne — należy unikać go w pętlach (problem N+1)
  • Explicit loading: ładowanie na żądanie z precyzyjną kontrolą
  • Projection z użyciem Select: najbardziej wydajne rozwiązanie w scenariuszach tylko do odczytu
  • Split queries: zapobiegają eksplozji kartezjańskiej przy dołączaniu wielu kolekcji
Bezpłatny start

Ucz się C# dzięki korepetycjom AI — za darmo

Pisz i uruchamiaj kod w przeglądarce, otrzymuj natychmiastową pomoc od korepetytora AI dostępnego 24/7 i kontynuuj naukę w sieci lub w aplikacji.

Kursy
93
Lekcje
346

Często zadawane pytania

Czy lekcja „Ładowanie eager, lazy i explicit” jest bezpłatna?

Tak — pełny tekst „Ładowanie eager, lazy i explicit” jest dostępny za darmo tutaj w sieci. Aby ćwiczyć ją interaktywnie (wbudowany edytor kodu i tutor AI dostępny 24/7) i odblokować resztę kursu C# Academy, przejdź na CoddyKit PRO. Kurs C# Academy zawiera 4 lekcji w sumie.

Co nauczysz się w „Ładowanie eager, lazy i explicit”?

Kontroluj moment ładowania powiązanych danych za pomocą Include, ThenInclude, proxy lazy loading i wywołań Load. Ćwiczysz C# Academy z praktycznym kodem, który uruchamiasz bezpośrednio w przeglądarce, a tutor AI dostępny 24/7 odpowiada na Twoje pytania podczas pracy nad lekcją.

Czy potrzebuję doświadczenia, aby zacząć C# Academy?

Nie wymagamy żadnego doświadczenia. C# Academy w CoddyKit jest strukturyzowany dla początkujących i zaawansowanych użytkowników, więc możesz zacząć tutaj lub od początku i uczyć się w swoim tempie. To lekcja 1 z 4.

Ile czasu zajmuje lekcja „Ładowanie eager, lazy i explicit”?

Większość lekcji CoddyKit trwa około 5–10 minut. Każda lekcja to mały, interaktywny krok, dzięki czemu robisz systematyczne postępy i zawsze wracasz dokładnie do tego samego miejsca — na webie i w aplikacji.

Czy mogę pisać i uruchamiać kod w tej lekcji C# Academy?

Tak. Każda lekcja C# Academy zawiera wbudowany edytor kodu, więc piszesz i uruchamiasz prawdziwy kod bezpośrednio w przeglądarce i od razu otrzymujesz sprzężenie zwrotne od AI — bez konfiguracji na komputerze.

Wszystkie lekcje w tym kursie

  1. Ładowanie eager, lazy i explicit
  2. Surowy SQL, procedury składowane i interpolacja
  3. Zapytania kompilowane i wydajność
  4. Globalne filtry zapytań i encje owned
← Powrót do C# Academy