10

I've created an Entity Framework model from the database. I have many-to-many relationship: User - UserRole - Role.

EF created UserRole entity and UserRoles navigation property in the User entity and in Role entity, but I'd rather have Roles in User and Users in Role. Is that possible to be designed through the Model Designer? How can I configure manually many-to-many relationship with a table in the middle?

Spook
  • 25,318
  • 18
  • 90
  • 167

1 Answers1

15

EF normally creates the intermediate model, if the UserRole table comprises of columns other than foreign keys for User and Role table.

So if you had just 2 columns in the UserRoles table, both FKs to the User and Role tables (not even a surrogate key), EF would create the Model as you wanted. (without any intermediate model) So that is one way to go, for automatic generation of the desired behavior. Have just 2 columns in the table.

But if you have other non-key columns (data) in this table, then what EF is doing is correct. You need the intermediate entity.

And in the case where you don't have any non-key columns, don't want to modify your DB anymore and don't need this middle table in your model, you could manually modify the OnModelCreating, to specify the Many-to-Many and hide the intermediate table.

Here are all the steps:

  1. Remove the intermediate table definition C# class from the model layer, and its references in DbContext and User and Role classes.
  2. Add a virtual Collection property in both User and Role class, for each other.

e.g. in the User class,

public virtual ICollection<Role> Roles { get; set; }

and in the User constructor

this.Roles = new HashSet<Role>();

// on the OnModelCreating method, add this snippet
modelBuilder.Entity<User>().HasMany<Role>(u => u.Roles)
                          .WithMany(r => r.Users)
                          .Map(ru => 
                                   {  
                                     ru.MapLeftKey("UserId");        
                                     ru.MapRightKey("RoleId"); 
                                     ru.ToTable("UserRole"); 
                                   });
Raja Nadar
  • 9,409
  • 2
  • 32
  • 41
  • 2
    I thought that including database structure was unnecessary, since I did the most standard many-to-many relationship possible. Yet, it seems, that it would help a lot, because I included `Id` column in the intermediate table. When I removed it, EF indeed discovered many-to-many relationships. Thanks! – Spook Feb 20 '16 at 18:50
  • yep. right now, if a primary key exists, EF by default creates the intermediate model, and we have to do work to undo it.. maybe the behavior could be the other way around.. by default, don't create this.. and if people really need the Id column in their C# code (for whatever reason) let them customize.. i guess there would be some rationale behind EF team's decision, including time/resource constraints/iterative development (my mind goes back to EF 1.0 back in 2007-2008) or maybe a many-2-many should be only the composite key. – Raja Nadar Feb 20 '16 at 19:04
  • It is worth noting, that primary key is required, but not as individual field, but as composition of fields with foreign keys. Otherwise you'll be able to read data, but not to write (using EF). – Spook Feb 20 '16 at 21:06
  • According to this post the OnModelCreating method may not be called. http://stackoverflow.com/q/33076291/135078 . Do you recommend one of the approaches mentioned? – Kelly S. French Jan 26 '17 at 21:20
  • This has a lot of potential for me, but my problem is the Map method is undefined. Is this no longer supported in EF7? How would I do this in EF7? – PHenry Aug 29 '23 at 19:09