0Pricing
C# Academy · Leçon

Chargement immédiat, différé et explicite

Contrôlez le moment où les données associées sont chargées avec Include, ThenInclude, les proxys de chargement différé et les appels explicites à Load.

Chargement immédiat, différé et explicite est une leçon C# Academy gratuite sur CoddyKit. Ceci est la leçon 1 sur 4. Tu peux lire la leçon complète ci-dessous gratuitement — puis la pratiquer en direct dans le navigateur avec un éditeur de code intégré et un tuteur IA 24/7. Elle fait partie du parcours d'apprentissage C# Academy, et ta progression se synchronise sur le web et l'application CoddyKit. Le cours C# Academy comprend 4 leçons au total.

Trois stratégies de chargement

EF Core propose trois stratégies pour charger les données associées : chargement anticipé (charger avec la requête), chargement différé (charger lors de l’accès) et chargement explicite (charger à la demande). Choisir la bonne stratégie permet d’éviter le problème N+1 et les allers-retours inutiles vers la base de données.

Chargement anticipé avec Include

Le chargement anticipé utilise Include() pour effectuer un JOIN avec les données associées dans la même requête SQL. Il s’agit de la stratégie la plus prévisible et elle évite les problèmes 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 pour les relations imbriquées

ThenInclude permet d’aller plus loin dans le graphe de navigation. Vous pouvez charger plusieurs niveaux dans une seule requête.

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();

Include avec filtre

EF Core 5+ permet de filtrer les données associées directement dans Include. Vous pouvez ainsi charger un sous-ensemble d’enfants sans requête distincte.

// 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();

Configuration du chargement différé

Le chargement différé charge automatiquement les propriétés de navigation lors de leur premier accès. Activez-le en installant le package Microsoft.EntityFrameworkCore.Proxies et en appelant 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>();
}

Le chargement différé en pratique (et le piège N+1)

Le chargement différé est pratique, mais dangereux dans les boucles : chaque accès déclenche une nouvelle requête SQL, ce qui provoque le problème N+1. Privilégiez toujours le chargement anticipé dans les scénarios avec des listes.

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();

Chargement explicite

Le chargement explicite vous permet de charger une propriété de navigation à la demande avec Entry().Collection().LoadAsync() ou Entry().Reference().LoadAsync(). Il est utile lorsque vous avez besoin de données associées uniquement dans certaines conditions.

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();

Chargement explicite avec filtre de requête

Vous pouvez filtrer un chargement explicite en utilisant .Query() avant d’appeler LoadAsync(), ce qui réduit la quantité de données renvoyées.

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);

Requêtes fractionnées pour les Include volumineux

Charger plusieurs collections dans une seule requête provoque une explosion cartésienne (les lignes se multiplient). Utilisez AsSplitQuery() pour envoyer une requête distincte par collection, puis effectuer la jointure en mémoire.

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);

Projection pour éviter de récupérer trop de données

Au lieu de charger des entités complètes avec toutes leurs relations, projetez les données vers un DTO avec Select. Vous obtenez ainsi exactement les données nécessaires en une seule requête optimisée.

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

Cas concret : choisir la bonne stratégie

Utilisez ce guide de décision en pratique :

  • Chargement immédiat + Include : vous avez toujours besoin des données associées, pages de liste
  • Projection : vues en lecture seule, réponses d'API — la solution la plus efficace
  • Chargement explicite : chargement conditionnel selon la logique de l'application
  • Chargement différé : à éviter dans les applications web ; à réserver aux applications de bureau ou aux scripts traitant de petits ensembles de données

Vérification rapide

Quel est le problème N+1 dans le contexte du chargement différé ?

Récapitulatif : stratégies de chargement

Points essentiels :

  • Chargement immédiat (Include) : charge les données en une seule requête — idéal lorsque les besoins d'accès sont prévisibles
  • Include avec filtre : ne charge qu'un sous-ensemble des éléments enfants — EF Core 5+
  • Chargement différé : pratique, mais risqué — à éviter dans les boucles (problème N+1)
  • Chargement explicite : charge les données à la demande avec un contrôle précis
  • Projection avec Select : la solution la plus efficace pour les scénarios en lecture seule
  • Requêtes séparées : évitent l'explosion cartésienne lorsque plusieurs collections sont incluses

Questions Fréquemment Posées

La leçon « Chargement immédiat, différé et explicite » est-elle gratuite ?

Oui — le texte complet de « Chargement immédiat, différé et explicite » est gratuit à lire ici sur le web. Pour la pratiquer de manière interactive (un éditeur de code intégré et un tuteur IA 24/7) et déverrouiller le reste du cours C# Academy, passe à CoddyKit PRO. Le cours C# Academy comprend 4 leçons au total.

Qu'est-ce que j'apprendrai dans « Chargement immédiat, différé et explicite » ?

Contrôlez le moment où les données associées sont chargées avec Include, ThenInclude, les proxys de chargement différé et les appels explicites à Load. Tu pratiques C# Academy avec du code pratique que tu exécutes directement dans le navigateur, et un tuteur IA 24/7 répond à tes questions au fur et à mesure que tu avances dans la leçon.

Dois-je avoir de l'expérience pour commencer C# Academy ?

Aucune expérience préalable n'est requise. C# Academy sur CoddyKit est structuré pour les débutants jusqu'aux apprenants avancés, donc tu peux commencer ici ou depuis le début et avancer à ton rythme. Ceci est la leçon 1 sur 4.

Combien de temps prend la leçon « Chargement immédiat, différé et explicite » ?

La plupart des leçons CoddyKit prennent environ 5–10 minutes. Chacune est courte et interactive, tu progresses régulièrement et tu repiques exactement où tu t'es arrêté sur le web et l'app.

Peux-tu écrire et exécuter du code dans cette leçon C# Academy ?

Oui. Chaque leçon C# Academy inclut un éditeur de code intégré, tu écris et exécutes du vrai code directement dans ton navigateur et tu reçois des retours IA instantanés — aucune configuration locale requise.

Toutes les leçons de ce cours

  1. Chargement immédiat, différé et explicite
  2. SQL brut, procédures stockées et interpolation
  3. Requêtes compilées et performances
  4. Filtres de requêtes globaux et entités possédées
← Retour à C# Academy