Many-to-Many Relationships in .NET Core 8: A Comprehensive Guide

nitish96
Nitish Sharma
Published on: March 9, 2025
Updated on: March 9, 2025
Many-to-Many Relationships in .NET Core 8: A Comprehensive Guide blog

In modern web applications, relationships between entities are a common occurrence. One of the most complex yet widely used relationships is the many-to-many relationship. In this blog post, we’ll explore how to implement and manage many-to-many relationships in .NET Core 8 using Entity Framework Core (EF Core).

What is a Many-to-Many Relationship?

A many-to-many relationship occurs when multiple records in one table are associated with multiple records in another table. For example:

  • Students and Courses: A student can enroll in multiple courses, and a course can have multiple students.

  • Books and Authors: A book can have multiple authors, and an author can write multiple books.

In relational databases, this relationship is typically implemented using a join table (also known as a bridging table or associative entity).


Setting Up the Project

Before diving into the code, ensure you have the following installed:

  • .NET Core 8 SDK

  • Visual Studio 2022 or Visual Studio Code

  • EF Core CLI tools (optional but recommended)

Create a new .NET Core 8 project:

dotnet new webapi -n ManyToManyDemo
cd ManyToManyDemo

Defining the Entities

Let’s use the Student and Course example to demonstrate a many-to-many relationship.

1. Student Entity

public class Student
{
    public int StudentId { get; set; }
    public string Name { get; set; }

    // Navigation property for the join table
    public ICollection<StudentCourse> StudentCourses { get; set; }
}

2. Course Entity

public class Course
{
    public int CourseId { get; set; }
    public string Title { get; set; }

    // Navigation property for the join table
    public ICollection<StudentCourse> StudentCourses { get; set; }
}

3. Join Table Entity (StudentCourse)

The join table is explicitly defined to manage the relationship between Student and Course.

public class StudentCourse
{
    public int StudentId { get; set; }
    public Student Student { get; set; }

    public int CourseId { get; set; }
    public Course Course { get; set; }
}

Configuring the DbContext

In your DbContext class, configure the many-to-many relationship using Fluent API.

public class ApplicationDbContext : DbContext
{
    public DbSet<Student> Students { get; set; }
    public DbSet<Course> Courses { get; set; }
    public DbSet<StudentCourse> StudentCourses { get; set; }

    public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options) : base(options)
    {
    }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        // Configure the many-to-many relationship
        modelBuilder.Entity<StudentCourse>()
            .HasKey(sc => new { sc.StudentId, sc.CourseId }); // Composite primary key

        modelBuilder.Entity<StudentCourse>()
            .HasOne(sc => sc.Student)
            .WithMany(s => s.StudentCourses)
            .HasForeignKey(sc => sc.StudentId);

        modelBuilder.Entity<StudentCourse>()
            .HasOne(sc => sc.Course)
            .WithMany(c => c.StudentCourses)
            .HasForeignKey(sc => sc.CourseId);
    }
}

Applying Migrations

Once the entities and DbContext are configured, create and apply the migrations:

dotnet ef migrations add InitialCreate
dotnet ef database update

This will generate the necessary tables in your database, including the StudentCourses join table.

Seeding Data

Let’s seed some initial data to test the relationship.

public static class SeedData
{
    public static void Initialize(ApplicationDbContext context)
    {
        if (!context.Students.Any())
        {
            var students = new List<Student>
            {
                new Student { Name = "John Doe" },
                new Student { Name = "Jane Smith" }
            };

            var courses = new List<Course>
            {
                new Course { Title = "Mathematics" },
                new Course { Title = "Physics" }
            };

            context.Students.AddRange(students);
            context.Courses.AddRange(courses);
            context.SaveChanges();

            var studentCourses = new List<StudentCourse>
            {
                new StudentCourse { StudentId = 1, CourseId = 1 },
                new StudentCourse { StudentId = 1, CourseId = 2 },
                new StudentCourse { StudentId = 2, CourseId = 1 }
            };

            context.StudentCourses.AddRange(studentCourses);
            context.SaveChanges();
        }
    }
}

Call the SeedData.Initialize method in your Program.cs or Startup.cs to populate the database.


Querying Many-to-Many Relationships

To retrieve data, you can use LINQ queries. For example:

Get All Courses for a Student

var studentWithCourses = context.Students
    .Include(s => s.StudentCourses)
    .ThenInclude(sc => sc.Course)
    .FirstOrDefault(s => s.StudentId == 1);

foreach (var course in studentWithCourses.StudentCourses)
{
    Console.WriteLine(course.Course.Title);
}

Get All Students for a Course

var courseWithStudents = context.Courses
    .Include(c => c.StudentCourses)
    .ThenInclude(sc => sc.Student)
    .FirstOrDefault(c => c.CourseId == 1);

foreach (var student in courseWithStudents.StudentCourses)
{
    Console.WriteLine(student.Student.Name);
}

Conclusion

Many-to-many relationships are a powerful feature in relational databases, and EF Core makes it easy to implement and manage them in .NET Core 8. By following the steps outlined in this blog, you can efficiently model and query complex relationships in your applications.

Comments

Login to leave a comment.

Build Software Application with Impact Hive