Many-to-Many Relationships in Entity Framework Core

Many-to-Many Relationships in Entity Framework Core using Fluent API

In this article, I will discuss How to Configure Many-to-Many Relationships between two Entities in Entity Framework Core using Fluent API with Examples. Please read our previous article, which discusses How to Configure One-to-Many Relationships in EF Core using Fluent API.

Many-to-Many Relationships in Entity Framework Core

In many-to-many relationships, a row in one table, let’s say TableA, can have many matching rows in another table, let’s say TableB and vice versa is also true, i.e., a row in TableB can have many matching rows in TableA. In Relational Databases, we can create many-to-many relationships by defining a third table, whose primary key consists of the foreign keys from tableA and tableB. So, here, the Primary Key is a composite Primary key.

In Entity Framework Core 5.0 and later versions, support for many-to-many relationships was reintroduced, allowing for simpler configurations without explicitly defining the joining table/entity in our model. This simplification makes it easier to model and work with many-to-many relationships.

Examples of Understanding Many-to-Many Relationships in EF Core Using Fluent API

In Entity Framework Core (EF Core), we can define a many-to-many relationship between entities using the Fluent API. Let’s configure a many-to-many relationship using the Fluent API in EF Core. Suppose we have two entities, Student and Course, where each student can enroll in multiple courses, and each course can have multiple students. So, let us create the following two entities.

Student.cs

First, create a class file named Student.cs and copy and paste the following code. Here, you can see we have a collection navigation property that is pointing to the Course entity.

namespace EFCoreCodeFirstDemo.Entities
{
    public class Student
    {
        public int StudentId { get; set; }
        public string? Name { get; set; }

        // Navigation property for the many-to-many relationship
        //One Student Can have Many Courses
        public List<Course> Courses { get; set; }
    }
}
Course.cs

Next, create another class file with the name Course.cs and then copy and paste the following code into it. Here, you can see we have a collection navigation property that is pointing to the Student entity.

namespace EFCoreCodeFirstDemo.Entities
{
    public class Course
    {
        public int CourseId { get; set; }
        public string? CourseName { get; set; }
        public string? Description { get; set; }
        //Navigation property for the many-to-many relationship
        //One Course Can be Taken by Many Students
        public List<Student> Students { get; set; }
    }
}

EF Core will automatically infer the many-to-many relationship with these entities due to the presence of navigation properties. However, if you want to configure the relationship explicitly using Fluent API, you can do so. So, modify the EFCoreDbContext class as follows to configure Many to Many Relationships using Fluent API. In this configuration, we use the HasMany, WithMany, and UsingEntity methods to define the many-to-many relationship between Student and Course.

using Microsoft.EntityFrameworkCore;
namespace EFCoreCodeFirstDemo.Entities
{
    public class EFCoreDbContext : DbContext
    {
        protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
        {
            //Configuring the Connection String
            optionsBuilder.UseSqlServer(@"Server=LAPTOP-6P5NK25R\SQLSERVER2022DEV;Database=EFCoreDB;Trusted_Connection=True;TrustServerCertificate=True;");
        }

        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            modelBuilder.Entity<Student>()
                .HasMany(s => s.Courses) // Student can enroll in many Courses
                .WithMany(c => c.Students) // Course can have many Students
                .UsingEntity(j => j.ToTable("StudentCourses"));  //Explicitly set the join table name
        }

        public DbSet<Student> Students { get; set; }
        public DbSet<Course> Courses { get; set; }
    }
}

In this Fluent API configuration:

  • HasMany(s => s.Courses): Specifies that a Student can have many Courses.
  • WithMany(c => c.Students): Specifies that a Course can have many Students.
  • UsingEntity(j => j.ToTable(“StudentCourses”)): Explicitly names the join table. If you don’t specify this, EF Core will use a default name based on the two entity names.

Note: Before Proceeding further, let us delete the EFCoreDB database using SSMS and Migration folder from our project.

With the above changes, open the Package Manager Console and Execute the add-migration and update-database commands as follows. You can give any name to your migration. Here, I am giving EFCoreDBMig1. The name that you are giving it should not be given earlier.

How to Configure Many-to-Many Relationships in EF Core using Fluent API with Examples

Now, if you verify the database, you should see the following.

Many-to-Many Relationships in Entity Framework Core

Next, modify the Main method of the Program class as follows:

using EFCoreCodeFirstDemo.Entities;
namespace EFCoreCodeFirstDemo
{
    internal class Program
    {
        static void Main(string[] args)
        {
            try
            {
                //Creating an Instance of Context Class
                using var context = new EFCoreDbContext();

                //Creating List of Courses
                var courses = new List<Course>
                {
                    new Course() { CourseName = "EF Core", Description="It is an ORM Tool"},
                    new Course() { CourseName = "ASP.NET Core", Description ="Open-Source & Cross-Platform" }
                };
                context.Courses.AddRange(courses);
                context.SaveChanges();
                Console.WriteLine("Courses Added");

                //Creating an Instance of Student Class
                var Pranaya = new Student() { Name = "Pranaya", Courses = courses };
                context.Students.Add(Pranaya);

                var Hina = new Student() { Name = "Hina", Courses = courses };
                context.Students.Add(Hina);

                context.SaveChanges();
                Console.WriteLine("Students Added");

                Console.ReadKey();
            }
            catch (Exception ex)
            {
                Console.WriteLine($"Error: {ex.Message}"); ;
            }
        }
    }
}

Now, run the above code and verify the StudentCourses table, and you should see the following.

How to Configure Many-to-Many Relationships in Entity Framework Core using Fluent API

Before EF Core 5.0

Suppose you are working with EF Core 4.0 and earlier versions. In that case, you need to configure the Many to Many relationship as follows: Here, we need to explicitly define the join table/entity in your model.

Student.cs

First, modify the Student class as follows. Here, you can see we have a collection navigation property that is pointing to the Course entity. Also, we have the StudentCourses property, which is required for Implementing Many-to-Many Relationships.

namespace EFCoreCodeFirstDemo.Entities
{
    public class Student
    {
        public int StudentId { get; set; }
        public string? Name { get; set; }
        //One Student Can have Many Courses
        public List<Course> Courses { get; set; } = new();
        //StudentCourses Collection Property for Implementing Many to Many Relationship
        public List<StudentCourse> StudentCourses { get; set; }
    }
}
Course.cs

Next, modify the Course class as follows. Here, you can see we have a collection navigation property that is pointing to the Student entity. Also, we have the StudentCourses property, which is required for Implementing Many-to-Many Relationships.

namespace EFCoreCodeFirstDemo.Entities
{
    public class Course
    {
        public int CourseId { get; set; }
        public string? CourseName { get; set; }
        public string? Description { get; set; }
        //One Course Can be Taken by Many Students
        public List<Student> Students { get; set; } = new();
        //StudentCourses Collection Property for Implementing Many to Many Relationship
        public List<StudentCourse> StudentCourses { get; set; }
    }
}

Next, define a new joining entity class that includes both entities’ foreign key and reference navigation properties. So, create a class file named StudentCourse.cs and copy and paste the following code. This entity has two foreign key properties (StudentId and CourseId) and two reference navigation properties pointing to the corresponding entities.

namespace EFCoreCodeFirstDemo.Entities
{
    public class StudentCourse
    {
        public int StudentId { get; set; }
        public Student Student { get; set; } = null!;
        public int CourseId { get; set; }
        public Course Course { get; set; } = null!;
    }
}

The foreign keys must be the composite primary key in the joining table. This can only be configured using Fluent API. So, modify the context class as follows to configure both the foreign keys in the joining entity as a composite key using Fluent API. In this configuration, we use the HasMany, WithMany, and UsingEntity methods to define the many-to-many relationship between Student and Course.

using Microsoft.EntityFrameworkCore;
namespace EFCoreCodeFirstDemo.Entities
{
    public class EFCoreDbContext : DbContext
    {
        protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
        {
            //Configuring the Connection String
            optionsBuilder.UseSqlServer(@"Server=LAPTOP-6P5NK25R\SQLSERVER2022DEV;Database=EFCoreDB;Trusted_Connection=True;TrustServerCertificate=True;");
        }

        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            modelBuilder.Entity<Student>()
                .HasMany(e => e.Courses) // Student can enroll in many Courses
                .WithMany(e => e.Students) // Course can have many Students
                
                // Define the joining table
                .UsingEntity<StudentCourse>(
                    //navigations needs to be configured explicitly 
                    l => l.HasOne<Course>(e => e.Course).WithMany(e => e.StudentCourses), //MapLeftKey
                    r => r.HasOne<Student>(e => e.Student).WithMany(e => e.StudentCourses)); //MapRightKey
        }

        public DbSet<Student> Students { get; set; }
        public DbSet<Course> Courses { get; set; }
    }
}

Note: Before Proceeding further, let us delete the EFCoreDB database using SSMS and Migration folder from our project.

With the above changes, open the Package Manager Console and Execute the add-migration and update-database commands as follows. You can give any name to your migration. Here, I am giving EFCoreDBMig1. The name that you are giving it should not be given earlier.

How to Configure Many-to-Many Relationships in EF Core using Fluent API with Examples

Now, if you verify the database, you should see the following.

How to Configure Many-to-Many Relationships in EF Core using Fluent API with Examples

Next, modify the Main method of the Program class as follows:

using EFCoreCodeFirstDemo.Entities;
namespace EFCoreCodeFirstDemo
{
    internal class Program
    {
        static void Main(string[] args)
        {
            try
            {
                //Creating an Instance of Context Class
                using var context = new EFCoreDbContext();

                //Creating List of Courses
                var courses = new List<Course>
                {
                    new Course() { CourseName = "EF Core", Description="It is an ORM Tool"},
                    new Course() { CourseName = "ASP.NET Core", Description ="Open-Source & Cross-Platform" }
                };
                context.Courses.AddRange(courses);
                context.SaveChanges();
                Console.WriteLine("Courses Added");

                //Creating an Instance of Student Class
                var Pranaya = new Student() { Name = "Pranaya", Courses = courses };
                context.Students.Add(Pranaya);

                var Hina = new Student() { Name = "Hina", Courses = courses };
                context.Students.Add(Hina);

                context.SaveChanges();
                Console.WriteLine("Students Added");

                Console.ReadKey();
            }
            catch (Exception ex)
            {
                Console.WriteLine($"Error: {ex.Message}"); ;
            }
        }
    }
}
Output:

How to Configure Many-to-Many Relationships in Entity Framework Core using Fluent API with Examples

If you check the StudentCourse database table, you’ll find this data.

How to Configure Many-to-Many Relationships in Entity Framework Core using Fluent API with Examples

With EF Core 5.0 and later, setting up many-to-many relationships has become more easier and less error-prone. The ability to implicitly handle the join table or further configure it using the Fluent API provides developers with flexibility while maintaining clarity in their data models.

In the next article, I will discuss Self-Referencing Relationships in Entity Framework Core using Fluent API with Examples. In this article, I explain How to Configure Many-to-Many Relationships in Entity Framework Core using Fluent API with Examples. I hope you enjoyed this Configure Many-to-Many Relationship in EF Core using Fluent API article.

Leave a Reply

Your email address will not be published. Required fields are marked *