Relazioni: uno-a-molti e molti-a-molti
Modelli ed esegua query su relazioni uno-a-molti e molti-a-molti con proprietà di navigazione e Fluent API.
Relazioni: uno-a-molti e molti-a-molti è una lezione C# Academy gratuita su CoddyKit. Questa è la lezione 4 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.
Relazioni in EF Core
EF Core modella tre tipi di relazioni tra le entità: uno-a-uno, uno-a-molti e molti-a-molti. Ognuna viene espressa tramite proprietà di navigazione e può essere configurata con la Fluent API.
Uno-a-molti: configurazione delle entità
Un Blog ha molti Posts. L'entità dipendente (Post) contiene la chiave esterna. Le proprietà di navigazione su entrambi i lati consentono di percorrere la relazione in entrambe le direzioni.
public class Blog
{
public int Id { get; set; }
public string Name { get; set; } = "";
public ICollection<Post> Posts { get; set; } = new List<Post>();
}
public class Post
{
public int Id { get; set; }
public string Title { get; set; } = "";
public int BlogId { get; set; } // FK
public Blog Blog { get; set; } = null!; // nav property
}Fluent API: uno-a-molti
EF Core deduce la relazione per convenzione, ma può esplicitarla con la Fluent API per maggiore chiarezza e per impostare il comportamento dell'eliminazione a cascata.
protected override void OnModelCreating(ModelBuilder mb)
{
mb.Entity<Blog>()
.HasMany(b => b.Posts)
.WithOne(p => p.Blog)
.HasForeignKey(p => p.BlogId)
.OnDelete(DeleteBehavior.Cascade);
}Query con Include (caricamento eager)
Utilizzi Include per caricare i dati correlati nella stessa query. Utilizzi ThenInclude per scendere più in profondità nel grafo di navigazione.
// Load blog with all its posts
var blog = await _db.Blogs
.Include(b => b.Posts)
.FirstOrDefaultAsync(b => b.Id == 1);
// Load posts with their comments too
var blogs = await _db.Blogs
.Include(b => b.Posts)
.ThenInclude(p => p.Comments)
.ToListAsync();Molti-a-molti senza entità di join
EF Core 5+ supporta le relazioni molti-a-molti senza un'entità di join esplicita. Crea automaticamente la tabella di join usando i nomi dei tipi di entità.
public class Student
{
public int Id { get; set; }
public string Name { get; set; } = "";
public ICollection<Course> Courses { get; set; } = new List<Course>();
}
public class Course
{
public int Id { get; set; }
public string Title { get; set; } = "";
public ICollection<Student> Students { get; set; } = new List<Student>();
}
// EF creates StudentCourse join table automaticallyMolti-a-molti con entità di join
Quando la tabella di join necessita di colonne aggiuntive (ad es. data di iscrizione, voto), crei un'entità di join esplicita con una chiave primaria composta.
public class Enrollment
{
public int StudentId { get; set; }
public Student Student { get; set; } = null!;
public int CourseId { get; set; }
public Course Course { get; set; } = null!;
public DateTime EnrolledAt { get; set; }
public decimal? Grade { get; set; }
}
// Fluent API config:
mb.Entity<Enrollment>().HasKey(e => new { e.StudentId, e.CourseId });
mb.Entity<Enrollment>().HasOne(e => e.Student).WithMany(s => s.Enrollments);
mb.Entity<Enrollment>().HasOne(e => e.Course).WithMany(c => c.Enrollments);Inserimento di dati correlati
Aggiunga le entità correlate alla raccolta dell'entità padre prima di chiamare SaveChangesAsync. EF Core gestisce automaticamente i valori delle FK.
var blog = new Blog { Name = "Dev Notes" };
blog.Posts.Add(new Post { Title = "Hello EF Core" });
blog.Posts.Add(new Post { Title = "Migrations Deep Dive" });
_db.Blogs.Add(blog);
await _db.SaveChangesAsync();
// Inserts Blog + 2 Posts with correct BlogId FKFiltraggio dei dati correlati
È possibile filtrare le proprietà di navigazione in LINQ. EF Core le traduce automaticamente in JOIN SQL.
// Blogs that have at least one published post
var popularBlogs = await _db.Blogs
.Where(b => b.Posts.Any(p => p.IsPublished))
.Select(b => new { b.Name, PostCount = b.Posts.Count(p => p.IsPublished) })
.OrderByDescending(b => b.PostCount)
.ToListAsync();Eliminazione a cascata
Con DeleteBehavior.Cascade, l'eliminazione dell'entità principale (Blog) elimina automaticamente tutte le entità dipendenti (Posts). Altre opzioni: SetNull, Restrict, NoAction.
// Delete a blog and all its posts
var blog = await _db.Blogs.FindAsync(1);
_db.Blogs.Remove(blog!);
await _db.SaveChangesAsync();
// Cascade: all Posts with BlogId=1 are also deletedEntità owned per gli oggetti valore
I tipi di entità owned sono ideali per gli oggetti valore (ad es. Address). Vengono archiviati nella stessa tabella del proprietario e non hanno un'identità indipendente.
public class Customer
{
public int Id { get; set; }
public string Name { get; set; } = "";
public Address ShippingAddress { get; set; } = new();
}
public class Address
{
public string Street { get; set; } = "";
public string City { get; set; } = "";
public string Country { get; set; } = "";
}
// Fluent API:
mb.Entity<Customer>().OwnsOne(c => c.ShippingAddress);Esempio reale: ordine con righe d'ordine
Un modello completo per l'e-commerce: Order (entità principale) con molti OrderLines (entità dipendenti), ognuno dei quali fa riferimento a un Product.
var order = await _db.Orders
.Include(o => o.Lines)
.ThenInclude(l => l.Product)
.FirstOrDefaultAsync(o => o.Id == orderId);
if (order is null) return Results.NotFound();
var summary = new
{
OrderId = order.Id,
Total = order.Lines.Sum(l => l.Quantity * l.Product.Price),
Items = order.Lines.Select(l => new
{
l.Product.Name,
l.Quantity,
LineTotal = l.Quantity * l.Product.Price
})
};
return Results.Ok(summary);Verifica rapida
Quando crea EF Core automaticamente una tabella di join senza un'entità di join esplicita?
Riepilogo: relazioni in EF Core
Punti chiave:
- Uno-a-molti: FK sull'entità dipendente; proprietà di navigazione su entrambi i lati; utilizzare Include per il caricamento
- Molti-a-molti (semplice): due proprietà di navigazione ICollection — EF Core crea automaticamente la tabella di join
- Molti-a-molti (con payload): entità di join esplicita con PK composta
- L'eliminazione a cascata controlla cosa accade alle entità dipendenti quando viene rimossa quella principale
- Le entità owned modellano gli oggetti valore nella stessa tabella del proprietario
Domande Frequenti
La lezione «Relazioni: uno-a-molti e molti-a-molti» è gratuita?
Sì — il testo completo di «Relazioni: uno-a-molti e molti-a-molti» è 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 «Relazioni: uno-a-molti e molti-a-molti»?
Modelli ed esegua query su relazioni uno-a-molti e molti-a-molti con proprietà di navigazione e Fluent API. 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 4 di 4.
Quanto tempo richiede la lezione «Relazioni: uno-a-molti e molti-a-molti»?
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
- Nozioni di base su DbContext e DbSet
- Migrazioni e gestione dello schema
- Operazioni CRUD con EF Core
- Relazioni: uno-a-molti e molti-a-molti