Tutorials ASP.NET Core Complete Tutorial (ShopNest)
EF Core Relationships — One-to-One, One-to-Many, Many-to-Many
Learn EF Core Relationships — One-to-One, One-to-Many, Many-to-Many in our free ASP.NET Core Complete Tutorial (ShopNest) series. Step-by-step explanations, examples, and interview tips on Toolliyo Academy.
On this page
Introduction
ShopNest Academy (School Management) connects Students, Courses, and Teachers through EF Core relationships. Modeling them correctly avoids duplicate data, orphaned records, and slow queries.
After this article you will
- Configure one-to-one, one-to-many, and many-to-many
- Use navigation properties both directions
- Apply Fluent API for cascade delete rules
- Choose eager, lazy, or explicit loading
- Detect and fix N+1 query problems
Prerequisites
- Article 16 — EF Core LINQ Queries
- ShopNest DbContext with Products/Orders from Articles 13–15
- SQL Server or LocalDB configured
Concept deep-dive
One-to-one
Student → StudentProfile (one profile per student). FK on dependent side.
public class Student
{
public int Id { get; set; }
public StudentProfile Profile { get; set; }
}
public class StudentProfile
{
public int Id { get; set; }
public int StudentId { get; set; }
public Student Student { get; set; }
}
One-to-many
Teacher → many Courses. FK TeacherId on Course.
Many-to-many (.NET 6+)
Students ↔ Courses via implicit join table, or explicit Enrollment entity with Grade and EnrolledAt.
public class Enrollment
{
public int StudentId { get; set; }
public Student Student { get; set; }
public int CourseId { get; set; }
public Course Course { get; set; }
public decimal? Grade { get; set; }
}
// Fluent API
modelBuilder.Entity<Enrollment>()
.HasKey(e => new { e.StudentId, e.CourseId });
Cascade delete
OnDelete(DeleteBehavior.Cascade) — deleting Teacher deletes Courses? Usually Restrict on business FKs to prevent accidents. Cascade OK for owned child rows (OrderLines).
Loading strategies
| Strategy | How | Risk |
|---|---|---|
| Eager | .Include() | Large joins if over-include |
| Lazy | Virtual + proxy | N+1 in loops |
| Explicit | context.Entry().Collection().Load() | Verbose but controlled |
Hands-on — ShopNest School Management System
- Scaffold Student, Course, Teacher, Enrollment entities.
- Migration with FK constraints and Restrict on Teacher→Course.
- Student details page: Include Profile + Enrollments.ThenInclude(Course).
- Log SQL — verify single query vs N+1.
Common errors & best practices
- Multiple cascade paths in SQL Server — use Restrict on one relationship.
- Missing inverse navigation — EF can still work but Fluent config is clearer.
- Many-to-many without join entity when you need extra columns on enrollment.
Interview questions
Q: N+1 problem?
A: 1 query for list + N queries for related data — fix with Include or projection.
Q: When explicit join entity?
A: When relationship has payload (Grade, EnrolledAt) or audit fields.
Q: Cascade delete safe?
A: Rarely on master data; OK for dependent detail rows owned by parent.
Summary
- Model relationships with navigation properties + FKs
- Fluent API controls cascade and join tables
- Include eagerly; avoid lazy loading in ASP.NET request paths
- Enrollment join entity for Student-Course grades
Previous: EF Core LINQ Queries
Next: EF Core Fluent API
FAQ
Does EF Core 8 still need join entity for many-to-many?
Optional — implicit join table works for simple M:N; use explicit entity when you need extra columns.
How detect N+1?
Enable sensitive data logging; count SQL statements per HTTP request.
Sign in to ask a question or upvote helpful answers.
No questions yet — be the first to ask!