I\'m coming across the same problem in my MVC 3 applications. I\'ve got a view to create an new product and that product can be assigned to one or more categories. Here are
Thanks @Slauma, that got me on the right track. Here is my Create and Edit post methods that detail how to manage the relationships (the edit is a bit trickier, because it has to add items that don't exist in the database and delete items that have been removed and do exist in the database). I added a SelectedCategories property (List of ints) to my ProductEditViewModel to hold the result from the form.
[HttpPost]
public ActionResult Create(ProductEditViewModel)
{
viewModel.Product.Categories = new List();
foreach (var id in viewModel.SelectedCategories)
{
var category = new Category { CategoryID = id };
db.Category.Attach(category);
viewModel.Product.Categories.Add(category);
}
if (ModelState.IsValid)
{
db.Products.Add(viewModel.Product);
db.SaveChanges();
return RedirectToAction("Index");
}
return View(new ProductEditViewModel(viewModel.Product, GetCategories()));
}
For the Edit method I had to query the database for the current product and then compare that with the viewModel.
[HttpPost]
public ActionResult Edit(ProductEditViewModel viewModel)
{
var product = db.Products.Find(viewModel.Product.ProductID);
if (ModelState.IsValid)
{
UpdateModel(product, "Product");
var keys = product.CategoryKeys; // Returns CategoryIDs
// Add categories not already in database
foreach (var id in viewModel.SelectedCategorys.Except(keys))
{
var category = new Category { CategoryID = id }; // Create a stub
db.Categorys.Attach(category);
product.Categories.Add(Category);
}
// Delete categories not in viewModel, but in database
foreach (var id in keys.Except(viewModel.SelectedCategories))
{
var category = product.Categories.Where(c => c.CategoryID == id).Single();
product.Categories.Remove(category);
}
db.SaveChanges();
return RedirectToAction("Index");
}
else
{
// Update viewModel categories so it keeps users selections
foreach (var id in viewModel.SelectedCategories)
{
var category = new Category { CategoryID = id }; // Create a stub
db.Categories.Attach(category);
viewModel.Product.Categories.Add(category);
}
}
return View(new ProductEditViewModel(viewModel.Product, GetCategories()));
}
It is more code that I was hoping it would be, but it is actually pretty efficient with using the stubs and only adding/deleting what has changed.