Creating Many-to-Many Mapping Using Code First (Entity Framework)

Introduction

Today I will share some of the information for creating many-to-many mappings using the Code First Approach. Using the Code First approach we follow mostly the case when our database is already created or with our DomainModel classes, we will create a database.

Creating Mapping

There is sometimes a situation where we need to create a many-to-many relationship. To do that we create a bridge table that holds the primary keys of both of the tables involved in the many-to-many relationship.



Figure 1: Creating Many-to-Many Mapping

In the Code First Approach, while we creating such a relationship, we create entries for both sides in an ICollection Objects here. First create a Console Application with a many-to-many relationship.



Figure 2: Create Application

Then install a Nuget package Entityframework as Figure 3.



Figure 3: Install Nuget Package

Now add a connection string in the App.config file as in the following:

  1. < connectionStrings >  
  2. < add name = "ConnString"  connectionString = "server=****;database=MVCSample;uid=**;password=***;Connection Timeout=3"  
  3. providerName = "System.Data.SqlClient" / >   
  4. < /connectionStrings>  
Then we create the classes for the model (DB entities) as in the following:
  1. public class Vendor   
  2. {  
  3.     public Vendor()  
  4.     {  
  5.         VendorProducts = new List < Product > ();  
  6.     }  
  7.   
  8.     public virtual int VendorId  
  9.     {  
  10.         get;  
  11.         set;  
  12.     }  
  13.     public virtual string VendorName  
  14.     {  
  15.         get;  
  16.         set;  
  17.     }  
  18.     public virtual ICollection < Product > VendorProducts  
  19.     {  
  20.         get;  
  21.         set;  
  22.     }  
  23. }  
  24.   
  25. public class Product  
  26. {  
  27.     public Product()   
  28.     {  
  29.         ProductVendors = new List < Vendor > ();  
  30.     }  
  31.     public virtual int ProductId   
  32.     {  
  33.         get;  
  34.         set;  
  35.     }  
  36.     public virtual string ProductName  
  37.     {  
  38.         get;  
  39.         set;  
  40.     }  
  41.     public virtual ICollection < Vendor > ProductVendors  
  42.     {  
  43.         get;  
  44.         set;  
  45.     }  
  46. }  
Then we will write the SuperMArketContext class that will be inherited by the DBContext class as in the following:
  1. public class SuperMarketContext: DbContext  
  2. {  
  3.     public DbSet < Product > Product   
  4.     {  
  5.         get;  
  6.         set;  
  7.     }  
  8.     public DbSet < Vendor > Vendor  
  9.     {  
  10.         get;  
  11.         set;  
  12.     }  
  13.   
  14.     public SuperMarketContext(): base("ConnString") {}  
  15.   
  16. }  
You will see in this Context class that first we declare two properties as in the following. Those properties will return a Dbset of those objects.
  1. public DbSet<Product> Product { getset; }  
  2. public DbSet<Vendor> Vendor { getset; }  
While in the contructor we provide the Connectionstring that we define in the App.config file.

Now if we run the sample application it will create the MVCSample database (as specified in the config) and the table will be created but the column name is not as per our expectations. See the figure below.



Figure 4: Solution Explorer

So we can solve this problem by overriding the OnModelCreating method and mapping using the Code First Fluent API as in the following:
  1. protected override void OnModelCreating(DbModelBuilder modelBuilder)   
  2. {  
  3.     modelBuilder.Entity < Vendor > ()  
  4.         .HasMany(v = > v.VendorProducts)  
  5.         .WithMany(p = > p.ProductVendors)  
  6.         .Map(  
  7.     m = >  
  8.     {  
  9.         m.MapLeftKey("VendorId");  
  10.         m.MapRightKey("ProductId");  
  11.         m.ToTable("VendorProduct");  
  12.     });  
  13. }  
In this mapping we start with the Vendor (alternatively we can start with the Products).
  • HasMany: Vendors has many products
  • WithMany: Products has many vendors
  • Map: It specifies for Code First how to build the relation table (so the bridge table sud can be generated here with VendorProduct and with the ToTable method)
  • m.MapLeft: since we start a Vendor so its vendorid sud can be the left key here (the primary key of the Vendor table)
  • m.MaprRight: will be the productid and will be the right key (the primary key of the Product table)
  • ToTable: will be the bridge table name

So if you run the code you will get the tables generated depending on your specified column name.

  1. static void Main(string[] args)   
  2. {  
  3.     using(SuperMarketContext db = new SuperMarketContext())  
  4.     {  
  5.         Product P1 = new Product();  
  6.         P1.ProductName = "Dell products";  
  7.   
  8.         Vendor V1 = new Vendor();  
  9.         V1.VendorName = "Vivek";  
  10.         V1.VendorProducts.Add(P1);  
  11.         db.Vendor.Add(V1);  
  12.         db.SaveChanges();  
  13.         Console.ReadKey();  
  14.     }  
  15. }  
The tables will be generated like this:



Figure 5: Output

So in this way you can create a many-to-many relationship with the Code First Approach very easily.

Thanks.


Similar Articles