How do I ModelBind a many-to-many relationship with MVC 3 and Entity Framework Code First?

前端 未结 3 1809
执念已碎
执念已碎 2021-01-06 13:46

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

3条回答
  •  無奈伤痛
    2021-01-06 14:16

    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.

提交回复
热议问题