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.