Home > Solution > Entity Framework 4.1: Many to Many Relationships (5)

Entity Framework 4.1: Many to Many Relationships (5)


This is part of a series of blog post about Entity Framework 4.1.  The past blog entries are:

In this article, I’ll cover the many to many relationships.

Let’s start with the easiest case, we’ll let EF infer the table mapping.  I model a many-to-many relationship between order and employee:

public class Order
{
    public int OrderID { get; set; }
    [Required]
    [StringLength(32, MinimumLength = 2)]
    public string OrderTitle { get; set; }
    [Required]
    [StringLength(64, MinimumLength=5)]
    public string CustomerName { get; set; }
    public DateTime TransactionDate { get; set; }
    public byte[] TimeStamp { get; set; }

    public virtual List<OrderDetail> OrderDetails { get; set; }
    public virtual List<Employee> InvolvedEmployees { get; set; }
}

public class Employee
{
    public int EmployeeID { get; set; }
    public string EmployeeName { get; set; }

    public virtual List<Order> Orders { get; set; }
}

I simply put a list of employees in order and a list of orders in employee.  Voila!  Here are the mapped tables:

image

Now, we might want to control two things:

  • The name of the relation table
  • The name of the two columns in the relation table

This can all be done with the following code:

modelBuilder.Entity<Employee>()
    .HasMany(e => e.Orders)
    .WithMany(e => e.InvolvedEmployees)
    .Map(m =>
    {
        m.ToTable("EmployeeOrder");
        m.MapLeftKey("EmployeeID");
        m.MapRightKey("OrderID");
    });

Basically, we say that an employee as many orders, that each employee has many orders (hence we have a many-to-many relationship).  We then go and say that the relation table should be named EmployeeOrder, the left key (from employee perspective, so the employee key) should be named employee-id and the right key order-id:

image

So there you go, you can control a table that doesn’t directly map to a class.

In terms of using such a model, it is quite straightforward and natural:

private static void ManyToMany()
{
    using (var context = new MyDomainContext())
    {
        var order = new Order
        {
            OrderTitle = "Pens",
            CustomerName = "Mcdo’s",
            TransactionDate = DateTime.Now,
            InvolvedEmployees = new List<Employee>()
        };
        var employee1 = new Employee { EmployeeName = "Joe", Orders = new List<Order>() };
        var employee2 = new Employee { EmployeeName = "Black", Orders = new List<Order>() };

        context.Orders.Add(order);

        order.InvolvedEmployees.Add(employee1);
        order.InvolvedEmployees.Add(employee2);

        context.SaveChanges();
    }

In this example I didn’t even bother to add the employees in the employees collection of the data context:  EF took care of that for me since they were referenced in a collection.

About these ads
Categories: Solution Tags:
  1. Paul
    July 8, 2011 at 05:01 | #1

    Thanks for the advice. How would you query that data? Say I want to get all orders by a specific employee?

    • July 8, 2011 at 13:00 | #2

      True I did not cover querying for that specific topic. For your specific example, it’s pretty simple (for a given employee id):

      var orders = from e in context.Employees
      where e.EmployeeID==theEmployeeID
      select e.Orders;

      or if you already have a reference to an employee ‘e’:

      e.Orders

      Is that what you meant?

      We could do something more complicated, for instance:

      var names = from o in context.Orders
      from e in o.InvolvedEmployees
      where o.OrderID == 2
      select e.EmployeeName;

      This would fetch, for the orderID ’2′ all the employee names related to it.

      Basically, as usual with EF, you can walk up and down relationships.

  2. jit
    December 29, 2011 at 11:48 | #3

    here i have order entity and employee entity. Now i want to check the employees in the order number 1. So i will go and search in orderemployee table. But i do not have orderemployee entity. How can i retrieve the data of this specific query

    • January 6, 2012 at 21:27 | #4

      Something like:

      var q = from o in context.Orders
      where o.OrderID==1
      select o.InvolvedEmployees;

      Despite ‘o.OrderID’ appearing in the query, it will never be fetched and materialized. It will only be translated in the SQL query, doing what you suggested, i.e. querying the relation table. Only employees will be materialized and returned.

      I hope that answered your question.

  3. Neetin Narendra
    February 6, 2012 at 04:36 | #5

    If the EmployeeOrder has some attributes of its own . Then will the conceptual model still be a many to many Relation or would it act like TWO one to many relation. Also will the conceptual model will have the entity EmployeeOrder .

    • February 7, 2012 at 11:18 | #6

      When you have more than a pure relation table, you need to make it into a first-class entity and have a one-to-many relationships from each related entity to it.

  4. Neetin Narendra
    February 7, 2012 at 23:58 | #7

    Thank you Vincent . I got the point.

  5. Daniel
    April 12, 2012 at 00:25 | #8

    Can someone explains how a many to many relationship should be used on a form view?

    • September 10, 2012 at 11:54 | #9

      Typically you won’t be able to directly bind your model to a view in that case. You’ll probably want to have something where you show an instance of type A (in a many-to-many relationship with type B) and a list of instances of type B and you let the user ‘add’ B-instances into A.

      In the model you then simply add B instances in the virtual list property of A.

  6. zomgman
    September 7, 2012 at 05:41 | #10

    Thanks for this example. How would you delete such relations with join models? In your example, when i want to remove the relationship between an Order and an Employee, how would i do that? i basically want to delete only the OrderEmployees join model.

  7. Ed
    September 13, 2012 at 22:32 | #12

    I noticed in your example that you created the employees. What if the same employee gets a new order? Won’t that wreck your employee table if you create the same employee again?

    • September 16, 2012 at 15:04 | #13

      Hi Ed,

      In your example, i.e. an existing employee gets a new oder, you need to load (select) the existing employee and add the new order on it.

      Another exemple… let say we have an existing employee & an existing order that have no relationship up to this point but we want to put them in relationship. We load both the employee and the order and add the employee in the Employees collection of the order. Or… alternatively, we add the order in the Orders collection of the employee.

      Basically, we don’t recreate object (record). We just add them to respective collections. Remember that those collections are not db-set collections on the db context, in which case that might actually recreate a record in the DB.

      • Edward
        September 17, 2012 at 18:09 | #14

        Vincent, thank you for explaining. I guess the first thing I need to do is get away from my ADO.Net mindset.
        Ed

  8. akhilesh
    October 19, 2012 at 11:15 | #15

    I wanted to implement same relation with additional column (Count) in EmployeeOrder table.
    That i am able to create but dont find a way to get and update “Count” column.

    • October 23, 2012 at 12:19 | #16

      Relation table (e.g. EmployeeOrder) can only contain primary keys from their related tables in order to be represented ‘implicitely’ in the object model. If we want more fields / columns, we need to represent them explicitely, e.g. as an EmployeeOrder object having two properties, Employee & Order (then Employee & Order objects could have a collection of Employee Orders) and the others (e.g. Count in your example).

  9. Dave Brennan
    November 20, 2012 at 15:01 | #17

    Sorry but I’m new to MVC, is there anywhere I can find an example of a view for creating the the many to many relationships.

  1. April 19, 2011 at 20:35 | #1
  2. April 19, 2011 at 20:36 | #2
  3. April 21, 2011 at 20:26 | #3
  4. May 2, 2011 at 12:18 | #4
  5. May 8, 2011 at 02:08 | #5
  6. December 14, 2011 at 08:42 | #6

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Connecting to %s

Follow

Get every new post delivered to your Inbox.

%d bloggers like this: