Caricamento eager, lazy ed esplicito
Controlli quando vengono caricati i dati correlati usando Include, ThenInclude, i proxy per il lazy loading e le chiamate esplicite a Load.
Caricamento eager, lazy ed esplicito è una lezione C# Academy gratuita su CoddyKit. Questa è la lezione 1 di 4. Puoi leggere la lezione completa qui gratuitamente — poi esercitati direttamente nel browser con un editor di codice integrato e un tutor IA disponibile 24/7. Fa parte del percorso di apprendimento C# Academy, e i tuoi progressi si sincronizzano tra il web e l'app CoddyKit. Il corso C# Academy include 4 lezioni in totale.
Tre strategie di caricamento
EF Core offre tre strategie per caricare i dati correlati: Eager Loading (caricamento insieme alla query), Lazy Loading (caricamento all'accesso) ed Explicit Loading (caricamento su richiesta). La scelta della strategia corretta evita il problema N+1 e i round-trip non necessari al database.
Caricamento eager con Include
Il caricamento eager utilizza Include() per eseguire il JOIN dei dati correlati nella stessa query SQL. È la strategia più prevedibile ed evita i problemi 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 per le relazioni annidate
ThenInclude consente di scendere più in profondità nel grafo di navigazione. È possibile caricare più livelli in un'unica query.
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 filtrato
EF Core 5+ supporta il filtraggio dei dati correlati all'interno di Include. Ciò consente di caricare un sottoinsieme degli elementi figlio senza una query separata.
// 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();Configurazione del lazy loading
Il lazy loading carica automaticamente le proprietà di navigazione la prima volta che vi si accede. Lo abiliti installando il pacchetto Microsoft.EntityFrameworkCore.Proxies e chiamando 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 in pratica (e la trappola N+1)
Il lazy loading è comodo, ma pericoloso nei cicli: ogni accesso esegue una nuova query SQL, causando il problema N+1. Negli scenari con liste, preferisca sempre il caricamento eager.
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();Caricamento esplicito
Il caricamento esplicito consente di caricare una proprietà di navigazione su richiesta usando Entry().Collection().LoadAsync() o Entry().Reference().LoadAsync(). È utile quando i dati correlati sono necessari solo in determinate condizioni.
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();Caricamento esplicito con filtro query
È possibile filtrare un caricamento esplicito usando .Query() prima di chiamare LoadAsync(), riducendo la quantità di dati restituiti.
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);Query suddivise per Include di grandi dimensioni
Caricare più raccolte in un'unica query causa un'esplosione cartesiana (le righe si moltiplicano). Utilizzi AsSplitQuery() per eseguire query separate per ogni raccolta, unendone i risultati in memoria.
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);Proiezione per evitare il caricamento eccessivo dei dati
Invece di caricare entità complete con tutte le relative relazioni, esegua una proiezione in un DTO con Select. In questo modo otterrà esattamente i dati necessari in un'unica query ottimizzata.
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 subqueriesNella pratica: scegliere la strategia giusta
Utilizzi questa guida decisionale nella pratica:
- Caricamento eager + Include: i dati correlati sono sempre necessari, ad esempio nelle pagine elenco
- Proiezione: viste di sola lettura, risposte API — la soluzione più efficiente
- Caricamento esplicito: caricamento condizionale basato sulla logica dell'applicazione
- Caricamento lazy: da evitare nelle app web; utilizzare solo per applicazioni desktop o script con insiemi di dati ridotti
Verifica rapida
Che cos'è il problema N+1 nel contesto del caricamento lazy?
Riepilogo: strategie di caricamento
Punti chiave:
- Caricamento eager (
Include): carica i dati con un'unica query — ideale per modalità di accesso prevedibili - Include filtrato: carica solo un sottoinsieme degli elementi figlio — EF Core 5+
- Caricamento lazy: comodo ma rischioso — da evitare nei cicli (problema N+1)
- Caricamento esplicito: carica i dati su richiesta con un controllo preciso
- Proiezione con
Select: la soluzione più efficiente negli scenari di sola lettura - Query suddivise: evitano l'esplosione cartesiana con più Include di raccolte
Domande Frequenti
La lezione «Caricamento eager, lazy ed esplicito» è gratuita?
Sì — il testo completo di «Caricamento eager, lazy ed esplicito» è gratuito qui sul web. Per esercitarvi in modo interattivo (un editor di codice integrato e un tutor IA 24/7) e sbloccare il resto del corso C# Academy, passa a CoddyKit PRO. Il corso C# Academy include 4 lezioni in totale.
Cosa imparerò in «Caricamento eager, lazy ed esplicito»?
Controlli quando vengono caricati i dati correlati usando Include, ThenInclude, i proxy per il lazy loading e le chiamate esplicite a Load. Eserciti C# Academy con codice pratico che esegui direttamente nel browser, e un tutor IA 24/7 risponde alle tue domande mentre lavori sulla lezione.
Ho bisogno di esperienza per iniziare C# Academy?
Non è richiesta alcuna esperienza precedente. C# Academy su CoddyKit è strutturato per principianti e studenti avanzati, quindi puoi iniziare da qui o dall'inizio e procedere al tuo ritmo. Questa è la lezione 1 di 4.
Quanto tempo richiede la lezione «Caricamento eager, lazy ed esplicito»?
La maggior parte delle lezioni CoddyKit richiede circa 5–10 minuti. Ogni lezione è breve e interattiva, quindi fai progressi costanti e riprendi esattamente da dove hai lasciato su web e app.
Posso scrivere ed eseguire codice in questa lezione C# Academy?
Sì. Ogni lezione C# Academy include un editor di codice integrato, quindi scrivi ed esegui codice reale direttamente nel tuo browser e ricevi feedback istantaneo dall'IA — nessuna configurazione locale necessaria.
Tutte le lezioni di questo corso
- Caricamento eager, lazy ed esplicito
- SQL nativo, stored procedure e interpolazione
- Query compilate e prestazioni
- Filtri globali per le query ed entità possedute