MVC 4编辑控制器/查看多对多关系和复选框

我正在使用ASP.NET MVC 4和Entity Framework,我正在寻找一些方法来创建多个关系和我的数据库中的复选框,用于创建/编辑控制器和视图,我已经找到了@Slauma答案的答案在MVC 4中创建- 多对多关系和复选框但是,我真的很想看到它如何扩展到编辑和删除function以及此解决方案中的其他一些合作伙伴。 有人可以请说明如何在Edit控制器方法中填充ClassificationSelectViewModel以获取“已选中”和“未选中”值吗? 这是一个Matt Flowers问题,也将解决我的问题。

以下是此答案的延续, 该答案描述了为实体SubscriptionCompany.之间具有多对多关系的模型Create GET和POST操作Company. 以下是Edit操作的过程,我将如何操作(除了我可能不会将所有EF代码放入控制器操作,而是将其提取到扩展和服务方法中):

CompanySelectViewModel保持不变:

 public class CompanySelectViewModel { public int CompanyId { get; set; } public string Name { get; set; } public bool IsSelected { get; set; } } 

SubscriptionEditViewModelSubscriptionCreateViewModel加上Subscription的密钥属性:

 public class SubscriptionEditViewModel { public int Id { get; set; } public int Amount { get; set; } public IEnumerable Companies { get; set; } } 

GET操作可能如下所示:

 public ActionResult Edit(int id) { // Load the subscription with the requested id from the DB // together with its current related companies (only their Ids) var data = _context.Subscriptions .Where(s => s.SubscriptionId == id) .Select(s => new { ViewModel = new SubscriptionEditViewModel { Id = s.SubscriptionId Amount = s.Amount }, CompanyIds = s.Companies.Select(c => c.CompanyId) }) .SingleOrDefault(); if (data == null) return HttpNotFound(); // Load all companies from the DB data.ViewModel.Companies = _context.Companies .Select(c => new CompanySelectViewModel { CompanyId = c.CompanyId, Name = c.Name }) .ToList(); // Set IsSelected flag: true (= checkbox checked) if the company // is already related with the subscription; false, if not foreach (var c in data.ViewModel.Companies) c.IsSelected = data.CompanyIds.Contains(c.CompanyId); return View(data.ViewModel); } 

Edit视图是Create视图加上Subscription的关键属性Id的隐藏字段:

 @model SubscriptionEditViewModel @using (Html.BeginForm()) { @Html.HiddenFor(model => model.Id) @Html.EditorFor(model => model.Amount) @Html.EditorFor(model => model.Companies)  @Html.ActionLink("Cancel", "Index") } 

选择公司的编辑器模板保持不变:

 @model CompanySelectViewModel @Html.HiddenFor(model => model.CompanyId) @Html.HiddenFor(model => model.Name) @Html.LabelFor(model => model.IsSelected, Model.Name) @Html.EditorFor(model => model.IsSelected) 

POST动作可能是这样的:

 [HttpPost] public ActionResult Edit(SubscriptionEditViewModel viewModel) { if (ModelState.IsValid) { var subscription = _context.Subscriptions.Include(s => s.Companies) .SingleOrDefault(s => s.SubscriptionId == viewModel.Id); if (subscription != null) { // Update scalar properties like "Amount" subscription.Amount = viewModel.Amount; // or more generic for multiple scalar properties // _context.Entry(subscription).CurrentValues.SetValues(viewModel); // But this will work only if you use the same key property name // in ViewModel and entity foreach (var company in viewModel.Companies) { if (company.IsSelected) { if (!subscription.Companies.Any( c => c.CompanyId == company.CompanyId)) { // if company is selected but not yet // related in DB, add relationship var addedCompany = new Company { CompanyId = company.CompanyId }; _context.Companies.Attach(addedCompany); subscription.Companies.Add(addedCompany); } } else { var removedCompany = subscription.Companies .SingleOrDefault(c => c.CompanyId == company.CompanyId); if (removedCompany != null) // if company is not selected but currently // related in DB, remove relationship subscription.Companies.Remove(removedCompany); } } _context.SaveChanges(); } return RedirectToAction("Index"); } return View(viewModel); } 

Delete操作不那么困难。 在GET操作中,您可以加载一些订阅属性以显示在删除确认视图上:

 public ActionResult Delete(int id) { // Load subscription with given id from DB // and populate a `SubscriptionDeleteViewModel`. // It does not need to contain the related companies return View(viewModel); } 

POST操作中,您加载实体然后将其删除。 不需要包含公司,因为在多对多关系中(通常)启用链接表上的级联删除,以便数据库将负责删除链接条目以及父Subscription

 [HttpPost, ActionName("Delete")] public ActionResult DeleteConfirm(int id) { var subscription = _context.Subscriptions.Find(id); if (subscription != null) _context.Subscriptions.Remove(subscription); return RedirectToAction("Index"); }