1

I wrote a many-to-many implementation based off of this tutorial and I'm unfortunately not able to actually save any values that are posted to my model.

[HttpPost]
public ActionResult Edit(User user, string[] selectedSites)
{
    if (ModelState.IsValid)
    {
        UpdateUserSites(selectedSites, user);
        context.Entry(user).State = EntityState.Modified;
        context.SaveChanges();
        return RedirectToAction("Index");
    }
    ViewBag.PossiblePartners = context.Partners;
    ViewBag.Sites = PopulateSelectedSiteData(user);
    return View(user);
}

and

private void UpdateUserSites(string[] selectedSites, User userToUpdate)
{
    // if no sites are selected, give the user a fresh empty list of sites
    if (selectedSites == null)
    {
        userToUpdate.Sites = new List<Site>();
        return;
    }

    var newSelectedSites = new HashSet<string>(selectedSites);
    var existingUserSites = new HashSet<int>(userToUpdate.Sites.Select(site => site.Id));

    foreach (var site in context.Sites)
    {
        if (newSelectedSites.Contains(site.Id.ToString()))
        {
            if (!existingUserSites.Contains(site.Id))
            {
                // add a new site to the user
                userToUpdate.Sites.Add(site);
            }
        }
        else
        {
            if (existingUserSites.Contains(site.Id))
            {
                // remove an existing site from the user
                userToUpdate.Sites.Remove(site);
            }
        }
    }
}

The UpdateuserSites function is definitely adding elements to the list, but after I attempt to save changes with context.SaveChanges() the database isn't getting updated.

Edit

I noticed a couple of things. One, when iterating over the Sites in my UpdateUserSites function, the site had some properties which were throwing exceptions. It had something to do with executing a query while iterating over an existing query set. I remedied this by changing context.Sites to context.Sites.ToList()

Two, my Create function works just fine. It adds a new user and adds a site to the user without a hitch. The new entry that I add, as well as existing entries, are editable except for the Sites property.

[HttpPost]
public ActionResult Create(User user, string[] selectedSites)
{
    if (ModelState.IsValid)
    {
        context.Users.Add(user);
        UpdateUserSites(selectedSites, user);
        context.SaveChanges();
        return RedirectToAction("Index");  
    }
    ViewBag.PossiblePartners = context.Partners;
    ViewBag.Sites = PopulateSelectedSiteData();
    return View(user);
}

Edit 2

This certainly has something to do with my entities and the current DbContext -- I added context.Users.Attach(user); right inside of the if(ModelState.IsValid) in the Edit function and now I am able to at least add sites to the user. Now I can't remove them. But at least I'm onto something.

Edit 3

I've reverted my Edit back to its original state, and instead modified my UpdateUserSites function with the following two lines

context.Users.Attach(userToUpdate);
context.Entry(userToUpdate).Collection(u => u.Sites).Load();

This attaches the current user to the context, loads all sites associated with it into the context (since the user being posted doesn't actually contain that information), and then everything works!

It would probably be best practice to post all the data against a single object, but I'm not sure how to do that.

Community
  • 1
  • 1
Brian D
  • 9,863
  • 18
  • 61
  • 96
  • Many to many associations are always independent associations in EF (vs. foreign key associations where you'd also have a primitive FK property like `SiteId`). Which means: you can only change them by manipulating the loaded elements. As you found out. – Gert Arnold Mar 03 '13 at 09:36

1 Answers1

0

I think that you need to check your ConnectionString The chances are your mdf file is probably overwritten each time you build your application that's why you think your changes are not persisted.

Travis G
  • 1,592
  • 1
  • 13
  • 18
  • It's not an issue of persisting across builds -- even redirecting back to the Index page after a successful `POST` results in no updates to the UserSites join table, no added sites to the user, etc. – Brian D Mar 03 '13 at 01:26
  • Can you try `savechanges` with `AcceptAllChangesAfterSave` option? – Travis G Mar 03 '13 at 02:12
  • No, it seems that the `SaveChanges()` only has one method which does not accept any parameters. – Brian D Mar 03 '13 at 02:24
  • yes u can.. please see the [link]( http://msdn.microsoft.com/en-us/library/system.data.objects.saveoptions.aspx) – Travis G Mar 03 '13 at 03:01
  • This is a `DbContext` object which has only one `SaveChanges()` function: http://msdn.microsoft.com/en-us/library/system.data.entity.dbcontext.savechanges(v=vs.103).aspx -- but the `DbContext.SaveChanges()` implementation already by default includes the options which you have suggested I try. – Brian D Mar 03 '13 at 03:10