Click here to Skip to main content
15,886,258 members
Articles / Web Development / ASP.NET
Tip/Trick

CRUD Many-to-Many Entity Framework

Rate me:
Please Sign up or sign in to vote.
5.00/5 (18 votes)
4 Apr 2015CPOL2 min read 138.6K   2.6K   35   18
CRUD over Association Entity that maps to association tables

Introduction

In many systems, it’s common modeling tables that have many-to-many relationships, this structure usually has three tables, two have primary keys and the third has two columns to relate these primary keys. The columns in the third table are, at the same time, primary key and foreign key. When mapping in Entity Framework designer, three tables becomes two entities.

Using the Code

The project has two layers to maintain as simple as possible:

  • Model: Layer that connects with database
  • UI.Web: ASP.NET WebForm project that references to Model and presents one aspx page with controls to demonstrate operations in database

Model and Mapping

I use just three tables in the example, Supplier, Product and ProductSupplier. In that structure, one supplier can supply one or many products and one product can be supplied by one or many suppliers.

The database diagram has three tables:

Image 1

But when mapping to EntityFramework, only two entities are present.

Image 2

Mapping entities add navigation property to represent that relation.

C#
namespace ManyToMany.Model
{
    using System;
    using System.Collections.Generic;
    
    public partial class Product
    {
        public Product()
        {
            this.Supplier = new HashSet<supplier>();
        }
    
        public long ProductID { get; set; }
        public string ProductName { get; set; }
		
		//navigation property to Supplier
        public virtual ICollection<supplier> Supplier { get; set; }
    }
}

namespace ManyToMany.Model
{
    using System;
    using System.Collections.Generic;
    
    public partial class Supplier
    {
        public Supplier()
        {
            this.Product = new HashSet<product>();
        }
    
        public long SupplierID { get; set; }
        public string SupplierName { get; set; }
    
		// navigation property to Product
        public virtual ICollection<product> Product { get; set; }
    }
}	

In the next sections, I will explain how to insert, delete, update and select this association table using LINQ to Entities.

Insert

There are two situations to insert data in tables that has a relationship many-to-many.

First, when data do not exist in tables, add instances to context, add an instance to navigation property and call SaveChanges method from context. That is possible because Entity Framework, at the time of insert, puts primary key value (if Identity, AutoIncrement) in correspondent entity’s property inserted.

C#
public void InsertWithoutData(Product prod, Supplier sup) 
{
	using (ManyToManyEntities conn = new ManyToManyEntities())
	{
		//add instances to context
		conn.Product.Add(prod);
		conn.Supplier.Add(sup);

		// add instance to navigation property
		prod.Supplier.Add(sup);

		//call SaveChanges from context to confirm inserts
		conn.SaveChanges();
	}
}	

Second case, data already exists in tables and it's necessary to relate them, pass the primary key to two tables/entity, add and attach to context object, add instance to entity navigation property and finally call SaveChanges method.

C#
public void InsertWithData(long productID, long supplierID) 
{
	using (ManyToManyEntities conn = new ManyToManyEntities())
	{

		/*
			* this steps follow to both entities
			* 
			* 1 - create instance of entity with relative primary key
			* 
			* 2 - add instance to context
			* 
			* 3 - attach instance to context
			*/

		// 1
		Product p = new Product { ProductID = productID };
		// 2
		conn.Product.Add(p);
		// 3
		conn.Product.Attach(p);

		// 1
		Supplier s = new Supplier { SupplierID = supplierID };
		// 2
		conn.Supplier.Add(s);
		// 3
		conn.Supplier.Attach(s);

		// like previous method add instance to navigation property
		p.Supplier.Add(s);

		// call SaveChanges
		conn.SaveChanges();
	}
}	

Delete

To delete relationship, instead of call Remove from context, we need to call it from navigation property.

C#
public void DeleteRelationship(long productID, long supplierID) 
{
	using (ManyToManyEntities conn = new ManyToManyEntities())
	{
		// return one instance each entity by primary key
		var product = conn.Product.FirstOrDefault(p => p.ProductID == productID);
		var supplier = conn.Supplier.FirstOrDefault(s => s.SupplierID == supplierID);

		// call Remove method from navigation property for any instance
		// supplier.Product.Remove(product);
		// also works
		product.Supplier.Remove(supplier);

		// call SaveChanges from context
		conn.SaveChanges();
	}
}

Update

The update statement compounds two statements, delete and insert, call delete and insert methods then.

C#
public void UpdateRelationship(long oldProductID, long oldSupplierID, 
	long newProductID, long newSupplierID) 
{
	DeleteRelationship(oldProductID, oldSupplierID);
	InsertWithData(newProductID, newSupplierID);
}	

Select

The select statement is a little bit different than normal, at first from use context to returns the first entity, then entity instance accesses the navigation property at the second from, this identifies that data comes from relationship table, but only ids do not bring useful information in this case, it’s necessary join to return useful data, or product or supplier.

DTOGenericObject is just an object to transport data from database to objects in webforms.

C#
public List<dtogenericobject> GetProductBySupplier(long supplierID)
{
	using (ManyToManyEntities conn = new ManyToManyEntities())
	{
		var result = (
			// instance from context
			from a in conn.Supplier
			// instance from navigation property
			from b in a.Product
			//join to bring useful data
			join c in conn.Product on b.ProductID equals c.ProductID
			where a.SupplierID == supplierID
			select new DTOGenericObject
			{
				ID = c.ProductID,
				Name = c.ProductName
			}).ToList();

		return result;
	}
}	

Points of Interest

When mapping association tables using Entity Framework, three tables involved become two entities. All operations should be with navigation property that was added in entities.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer
Brazil Brazil
Since 2009 acting in development of systems. I love what I do professionally and want always learn more. Languages, technologies and frameworks: C#, VB.NET, ASP.NET, JQuery, EntityFramework, Sql Server, Oracle 11g, Source Safe, TFS and ClearCase.

Comments and Discussions

 
BugProblem with UPDATE Pin
Member 1336022425-Jun-20 22:25
Member 1336022425-Jun-20 22:25 
QuestionSystem.InvalidOperationException: 'Unable to determine the relationship represented by navigation property Pin
Member 1373893515-Jan-19 0:25
Member 1373893515-Jan-19 0:25 
QuestionInsertWithoutData Pin
Luis M. Teijón21-Jan-17 14:15
Luis M. Teijón21-Jan-17 14:15 
Questionrunning the project Pin
Member 1250268230-Oct-16 6:03
Member 1250268230-Oct-16 6:03 
AnswerRe: running the project Pin
Jean Carlo S. Passos6-Nov-16 8:18
professionalJean Carlo S. Passos6-Nov-16 8:18 
GeneralRe: running the project Pin
Member 125026827-Nov-16 7:45
Member 125026827-Nov-16 7:45 
GeneralRe: running the project Pin
Member 125026827-Nov-16 7:51
Member 125026827-Nov-16 7:51 
GeneralRe: running the project Pin
Jean Carlo S. Passos5-Dec-16 11:11
professionalJean Carlo S. Passos5-Dec-16 11:11 
QuestionUpdating of many to many with existing items . Pin
Member 1115003220-Jan-16 10:11
Member 1115003220-Jan-16 10:11 
QuestionInsertWithoutData seems not working with latest EF and .NET MVC Pin
Member 117685476-Nov-15 23:19
Member 117685476-Nov-15 23:19 
AnswerRe: InsertWithoutData seems not working with latest EF and .NET MVC Pin
Jean Carlo S. Passos8-Dec-15 12:04
professionalJean Carlo S. Passos8-Dec-15 12:04 
GeneralMy vote of 5 Pin
Humayun Kabir Mamun7-Apr-15 2:06
Humayun Kabir Mamun7-Apr-15 2:06 
QuestionAdditional field in ProductSupplier Pin
Hamid5-Apr-15 0:18
Hamid5-Apr-15 0:18 
AnswerRe: Additional field in ProductSupplier Pin
Jean Carlo S. Passos5-Apr-15 3:49
professionalJean Carlo S. Passos5-Apr-15 3:49 
GeneralRe: Additional field in ProductSupplier Pin
Hamid6-Apr-15 22:09
Hamid6-Apr-15 22:09 
GeneralRe: Additional field in ProductSupplier Pin
Jean Carlo S. Passos7-Apr-15 4:46
professionalJean Carlo S. Passos7-Apr-15 4:46 
GeneralRe: Additional field in ProductSupplier Pin
Hamid13-Apr-15 21:45
Hamid13-Apr-15 21:45 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.