Relacionamentos: um para muitos e muitos para muitos
Modele e consulte relacionamentos um para muitos e muitos para muitos com propriedades de navegação e a Fluent API.
Relacionamentos: um para muitos e muitos para muitos é uma aula grátis de C# Academy no CoddyKit. Esta é a aula 4 de 4. Você pode ler a aula completa abaixo gratuitamente — depois pratica ao vivo no navegador com um editor de código integrado e um tutor de IA 24/7. Faz parte do caminho de aprendizado de C# Academy, e seu progresso é sincronizado entre a web e o app CoddyKit. O curso de C# Academy inclui 4 aulas no total.
Relacionamentos no EF Core
EF Core modela três tipos de relacionamentos entre entidades: um para um, um para muitos e muitos para muitos. Cada um é expresso com propriedades de navegação e pode ser configurado opcionalmente com a Fluent API.
Um para muitos: configuração da entidade
Um Blog tem muitos Posts. O dependente (Post) contém a chave estrangeira. As propriedades de navegação em ambos os lados permitem percorrer o relacionamento em qualquer direção.
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: um para muitos
EF Core infere o relacionamento por convenção, mas você pode especificá-lo com a Fluent API para obter clareza e definir o comportamento de exclusão em 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);
}Consultando com Include (carregamento antecipado)
Use Include para carregar dados relacionados na mesma consulta. Use ThenInclude para avançar na hierarquia de navegação.
// 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();Muitos para muitos sem entidade de junção
EF Core 5+ oferece suporte a relacionamentos muitos para muitos sem uma entidade de junção explícita. Ele cria a tabela de junção automaticamente usando os nomes dos tipos de entidade.
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 automaticallyMuitos para muitos com entidade de junção
Quando a tabela de junção precisa de colunas adicionais (por exemplo, data de matrícula e nota), crie uma entidade de junção explícita com uma chave primária 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);Inserindo dados relacionados
Adicione entidades relacionadas à coleção do pai antes de chamar SaveChangesAsync. EF Core lida automaticamente com os valores de 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 FKFiltrando dados relacionados
Você pode filtrar propriedades de navegação em LINQ. EF Core traduz essas expressões automaticamente em operações JOIN no 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();Exclusão em cascata
Com DeleteBehavior.Cascade, excluir a entidade principal (Blog) exclui automaticamente todas as entidades dependentes (Post). Outras opções: 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 deletedEntidades pertencentes para objetos de valor
Os tipos de entidade pertencentes são excelentes para objetos de valor (por exemplo, Address). Eles são armazenados na mesma tabela que o proprietário e não têm uma identidade independente.
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);Na prática: pedido com itens de linha
Um padrão completo de comércio eletrônico: Order (principal) com muitos OrderLines (dependentes), cada um referenciando um 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ção rápida
Quando EF Core cria automaticamente uma tabela de junção sem uma entidade de junção explícita?
Revisão: relacionamentos no EF Core
Principais conclusões:
- Um para muitos: FK no dependente; navegação em ambos os lados; use Include para carregar
- Muitos para muitos (simples): duas navegações ICollection — EF Core cria automaticamente a tabela de junção
- Muitos para muitos (com dados adicionais): entidade de junção explícita com PK composta
- A exclusão em cascata controla o que acontece aos dependentes quando a entidade principal é removida
- Entidades pertencentes modelam objetos de valor na mesma tabela que o proprietário
Perguntas Frequentes
A aula “Relacionamentos: um para muitos e muitos para muitos” é grátis?
Sim — o texto completo de “Relacionamentos: um para muitos e muitos para muitos” é grátis para ler aqui na web. Para praticá-la interativamente (um editor de código integrado e um tutor de IA 24/7) e desbloquear o restante do curso de C# Academy, atualize para CoddyKit PRO. O curso de C# Academy inclui 4 aulas no total.
O que vou aprender em “Relacionamentos: um para muitos e muitos para muitos”?
Modele e consulte relacionamentos um para muitos e muitos para muitos com propriedades de navegação e a Fluent API. Você pratica C# Academy com código prático que executa diretamente no navegador, e um tutor de IA 24/7 responde suas dúvidas enquanto trabalha na aula.
Preciso ter experiência prévia para começar C# Academy?
Nenhuma experiência prévia é necessária. C# Academy no CoddyKit é estruturado para alunos iniciantes até avançados, então você pode começar aqui ou desde o início e aprender no seu ritmo. Esta é a aula 4 de 4.
Quanto tempo leva a aula “Relacionamentos: um para muitos e muitos para muitos”?
A maioria das aulas CoddyKit leva cerca de 5–10 minutos. Cada uma é compacta e interativa, então você faz progresso constante e retoma exatamente de onde parou entre web e app.
Posso escrever e executar código nesta aula de C# Academy?
Sim. Cada aula de C# Academy inclui um editor de código integrado, então você escreve e executa código real direto no navegador e recebe feedback de IA instantaneamente — nenhuma configuração local necessária.
Todas as aulas deste curso
- Fundamentos de DbContext e DbSet
- Migrações e gerenciamento de esquema
- Operações CRUD com EF Core
- Relacionamentos: um para muitos e muitos para muitos