Many-to-Many Relationships in Entity Framework Core

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

In this article, I am going to 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, where we discussed 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.

Note: There are no default conventions available in Entity Framework Core that automatically configure a many-to-many relationship. You must configure it using Fluent API.

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. The Fluent API provides a way to configure the relationships and the mappings between entities more flexibly and more detailedly than using only data annotations.

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 with the name Student.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 Course entity.

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; } = new();
    }
}
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; }
        //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; } = new();
    }
}

Next, define a new joining entity class that includes both entities’ foreign key property and reference navigation property. So, create a class with the name StudentCourse.cs and then copy and paste the following code into it. This entity has two foreign key properties (StudentId and CourseId) and a navigation reference property 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 method along with 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 in place, open Package Manager Console and Execute the following add-migration and update-database commands. 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

In the next article, I am going to 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 *