4
votes

How do I delete a record in a junction table within Entity Framework 5?

When reverse engineering my DataContext, Entity Framework seems to have recognized my junction table and automatically added Collections to my Models to represent the M:M relationship. This is great when adding items, as I can simply build my entire Entity and everything gets inserted properly. Perfect.

However, I'm stumped on removing a relationship. For example, an Activity can have multiple Contacts associated to it, and this is linked using a junction table (dbo.ActivityContacts) that consists of the columns:

  • ActivityID
  • ContactID

Both my Activity and Contact models have been updated by EF with Collections to represent the other. For example, my Activity model looks like this:

    public class Activity
    {
        public int ActivityID { get; set; }
        public string Subject { get; set; }
        public virtual ICollection<Contacts> Contacts { get; set; }
    }

In a non-EF environment, I would simply delete the record from the junction table and move on with my day. However, it seems I cannot access the junction table directly using EF, so I'm a tad confused on how to remove the record (relationship).

How can I properly remove a record from a junction table in Entity Framework?

4

4 Answers

2
votes

Agree with @Chris.

Another solution is to do:

context.Entry(activity).State = EntityState.Deleted;
2
votes

Entity Framework should remove the record for you, if you remove the associated object from either side of the relationship.

Assuming you've obtained this Activity instance from your context and want to remove a specific Contact with a known ID:

unwantedContact = context.Contacts.Find(contactID);
myActivity.Contacts.Remove(unwantedContact);

context.SaveChanges();

Should delete the record in your junction table, unless I'm being daft.

1
votes

ali golshani did a good job providing a solution. Let me try to expand on it a little more. In my scenario I have two list boxes where you can move items left or right (selected or not selected)

The 'dto' object below is sent from the client. It's checking the selected state for each item in the list. If anyone knows of any way to improve this any more please leave feedback.

file_appender selectedAppender = context.file_appender.Find(dto.Id);

int[] ids = dto.Loggers.Where(x => !x.Selected).Select(x => x.Id).ToArray();
var loggers_to_delete = selectedAppender.logger.Where(x => ids.Contains(x.id));
loggers_to_delete.ToList().ForEach(x =>
{
    selectedAppender.logger.Remove(x);
});

ids = dto.Loggers.Where(x => x.Selected).Select(x => x.Id).ToArray();
var loggers_to_add = context.logger.Where(x => ids.Contains(x.id));
loggers_to_add.ToList().ForEach(x =>
{
    selectedAppender.logger.Add(x);
});

Lets look at another example....This one is for a list box with embedded check boxes (a little simpler). Honestly this could probably be applied to the solution above to make easier to read code.

enter image description here

protected void saveRelatedConnectors(test_engine testEngine, List<int> connectorTypes)
    var stepConnectorsToDelete = testEngine.step_connector.Where(x => (connectorTypes.Count == 0) || 
        (connectorTypes.Count != 0 && !connectorTypes.Contains(x.id)));
    stepConnectorsToDelete.ToList().ForEach(x =>
    {
        testEngine.step_connector.Remove(x);
    });

    var stepConnectorsToAdd = entities.step_connector.Where(x => connectorTypes.Contains(x.id));
    stepConnectorsToAdd.ToList().ForEach(x =>
    {
        testEngine.step_connector.Add(x);
    });

    entities.SaveChanges();
0
votes
contact_to_delete = context.Contacts.Find(contactID);
selected_activity = context.Activity.Find(ActivityID);
context.Entry(selected_activity).Collection("Activity").Load();
selected_activity.Contacts.Remove(contact_to_delete);
db.SaveChanges();