I've got this all working, but it seems to be quite long-winded, and I thought I'd post here and see if I'm doing it wrong...

I have a M:M relationship between an Installer and a MasterInstance. The classes (code-first) look like:

public class MasterInstance
    .. rest of fields here ..
    public virtual ICollection<Installer> PermittedInstallers { get; set; }

public class Installer
    .. rest of fields here ..
    public virtual ICollection<MasterInstance> PermittedMasterInstances { get; set; }

I want to be able to edit these in my Installer view, using a multi-list box. So, I create a ViewModel for what I need:

public class InstallerViewModel
    public Installer Installer { get; set; }
    public List<MasterInstance> PermittedMasterInstances { get; set; }
    public int[] SelectedMasterInstances { get; set; }

And then I place this in my view like so so that I can select the instances for my installer:

<div class="editor-field">
    @Html.ListBoxFor(model => model.SelectedMasterInstances,(Model.PermittedMasterInstances).Select(option => new SelectListItem {
        Text = option.Name, 
        Value = option.MasterInstanceId.ToString()

In the controller, for the edit action, I need to set this view model up:

var installer = context.Installers.Include(i => i.PermittedMasterInstances).Single(x => x.InstallerId == installerId);
            InstallerViewModel model = new InstallerViewModel
                                               Installer = installer,
                                               PermittedMasterInstances = context.MasterInstances.ToList(),
                                               SelectedMasterInstances = installer.PermittedMasterInstances.Select(i => i.MasterInstanceId).ToArray()
return View(model);

Finally, on the post of the edit, I need to delete any relationships that are no longer there and add the new ones:

// Grab the model from the viewmodel and attach to the context
var installer = installerModel.Installer;

// Load the related records (dont know why Lazy Loading wouldn't kick in here)
context.Entry(installer).Collection(i => i.PermittedMasterInstances).Load();
// Iterate and delete existing relationships
var instancesToDelete = installer.PermittedMasterInstances.Where(mi => !installerModel.SelectedMasterInstances.Contains(i.MasterInstanceId)).ToList();
instancesToDelete.ForEach(mi => installer.PermittedMasterInstances.Remove(mi));

// Now loop through an int[] and add those new relations, WITHOUT the pain of fetching them from the DB
foreach (var permittedMasterInstanceId in installerModel.SelectedMasterInstances)
    if (!installer.PermittedMasterInstances.Any(pmi => pmi.MasterInstanceId == permittedMasterInstanceId))
        var masterInstance = new MasterInstance {MasterInstanceId = permittedMasterInstanceId};

// We're done - save and finish.
context.Entry<Installer>(installer).State = EntityState.Modified;

So this works... But, it seemed like a lot of effort, is this the right/best way to achieve it?

  • \$\begingroup\$ This is exactly how ive approached this problem in the past, its a bit ugly but ive never fund a better way \$\endgroup\$
    – undefined
    Feb 15, 2012 at 21:42

1 Answer 1


I know this is an old question, but I think the problem is timeless. Many to many associations (i.e. without junction class) in Entity Framework are always independent associations, so you can only establish or remove them by manipulating object collections, not primitive key values. Inefficiency is inherent to the implementation.

But it is not prohibited to have a second context that only contains junction tables.

You could create a context that contains the MasterInstanceInstaller junction table and use this to update the associations in the most efficient way you can get using EF:

var installer = installerModel.Installer;

var junctions = context.MasterInstanceInstallers
                       .Where(x => x.InstallerId == installer.InstallerId)

// Delete deselected instances.
foreach(var mi in junctions
                  .Where(x => !installerModel.SelectedMasterInstances

// Add newly selected instances.
foreach(int instanceId in installerModel.SelectedMasterInstances
                                        .Except(junctions.Select(j => j.MasterInstanceId)))
    context.MasterInstanceInstallers.Add(new MasterInstanceInstaller
                                                InstallerId = installer.InstallerId,
                                                MasterInstanceId = instanceId

Now, if necessary you can populate the updated many to many association through the main context.


Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.