6

I have three tables in my sample database:

Users

  • ID
  • Username
  • Password

Roles

  • ID
  • Name
  • Description

UserRoles

  • UserID
  • RoleID

UserRoles is a lookup table to simulate a many to many relationship. Adding records to this table allows one to associate records in Users and Roles. My problem is that in Entity Framework it correctly interprets this as a many to many relationship and abstracts away that lookup table.

This works great most of the time, but I'm not sure what to do when I want to add/delete entries from that lookup table. I can delete roles or users but that actually deletes the objects not just their association with each other.

I do know of one option to add a dummy column to the UserRoles lookup table. That will force Entity Framework to turn the lookup table into a full-blown entity, allowing me to add and remove them as lone objects. But I have no need for a dummy column and this seems like a hack. I am looking for better suggestions.

Community
  • 1
  • 1
CatDadCode
  • 58,507
  • 61
  • 212
  • 318

3 Answers3

7

It should look something like this:

To Remove Relationship

user.Roles.Remove(existingRoleEntity);

To Add Relationship

user.Roles.Add(existingRoleEntity);
CatDadCode
  • 58,507
  • 61
  • 212
  • 318
StriplingWarrior
  • 151,543
  • 27
  • 246
  • 315
3

You can use the navigation properties on the entities:

(assuming u is a User object):

using (var db = new UserEntities())
{
    Role roleToRemove = db.Roles.Single(SelectRoleHere);
    User user = db.Users.Single(SelectUserHere);
    user.Roles.Remove(roleToRemove);
    db.SaveChanges();
}

EDIT - Added SaveChanges based on Slauma's comment.

Leom Burke
  • 8,143
  • 1
  • 35
  • 30
1

I have solved this problem before by simply adding an Private Key Identifier Auto-Increment column to the lookup table as Entity Framework will always hide lookup tables that only contain 2 columns with foreign keys to the end tables. Sometimes you need to add a lookup entry directly yourself via Entity Framework and this will help you achieve that.

Update From Question Author

I just wanted to provide an update on my own implementation of this answer. I added an identity column to the lookup table and created a unique key over the two foreign key columns to prevent duplicate relationship entries in the table. My model now looks like this:

http://www.codetunnel.com/content/images/ManyToManyDynamic.jpg

The only thing that sucks is to get a collection of all associated Roles I would have to do this:

List<Role> roles = new List<Role>();
foreach (UserRole userRole in myUser.UserRoles)
    roles.Add(userRole.Role);

It's a little more work but unless there is an equivalent to user.Roles.Remove(role) (something like user.Roles.Associate(existingRoleEntity)) then this is my only option.

Update:

List<Role> roles = new List<Role>();
foreach (UserRole userRole in myUser.UserRoles)
    roles.Add(userRole.Role);

Can be achieved via:

IEnumerable<int> roleIDs = myUser.UserRoles.Select(r => r.RoleID);
IEnumerable<Role> roles = Entityies.Roles.Where(r => roleIDs.Contains(r.roleID);

You can always use a public partial class to extend User to have a property to return all roles using the above. Click the link for details of the public partial class stuff I gave on another question.

Community
  • 1
  • 1
Chris Snowden
  • 4,982
  • 1
  • 25
  • 34
  • 1
    I didn't think about making the dummy column a PK identifier column. Doesn't seem so superfluous this way. I do need to add and remove from this so making it an entity makes sense. Great answer! – CatDadCode Jul 19 '11 at 15:23
  • @Alex Ford: You really destroy the many-to-many relation this way. You had to introduce a new artificial entity and then make two 1-to-many relationships. The join table in many-to-many relations in EF is supposed to be hidden in the model. – Slauma Jul 19 '11 at 15:30
  • @Slauma, doing this does allow you to add many `Roles` to a `User`, for example, without loading the `User` and adding Roles to it. It can be useful to add them directly and in more complicated cases can be needed. – Chris Snowden Jul 19 '11 at 15:34
  • @Slauma, I know I destroyed the abstraction. However, it is merely an extra step to do `User.UserRoles.Single(some condition).Role` and gives me the ability to add relationships as well as delete them. Unless you can provide a way to add relationships to the lookup table while maintaining the abstraction, then this is my only option. – CatDadCode Jul 19 '11 at 15:39
  • Doing this would also allow you to add the same `Role` to a `User` multiple times, which doesn't really model a many-to-many relationship very well. Unless you have specific information that you want to attach to the relationship, stick with the way Entity Framework has designed it. See the comment on my post for info on how to add the relationship. – StriplingWarrior Jul 19 '11 at 15:41
  • @StriplingWarrior, if you paid attention to my edit of this answer, I added a unique key to the two foreign key columns preventing them from having duplicates. Despite that, your answer is much cleaner for our purposes. – CatDadCode Jul 19 '11 at 15:50
  • @Chris, extending the class is a good idea. Thank you for the answer, even though the default EF behavior is cleaner in my case I can see this being useful for more complicated scenarios. +1 – CatDadCode Jul 19 '11 at 15:56
  • @Alex Ford, as you said this is useful if you need it which I have done in the past. If you can manage with the default hidden link table then obviously you should do. – Chris Snowden Jul 19 '11 at 15:59