MVC 4编辑控制器/查看多对多关系和复选框
我正在使用ASP.NET MVC 4和Entity Framework,我正在寻找一些方法来创建多个关系和我的数据库中的复选框,用于创建/编辑控制器和视图,我已经找到了@Slauma答案的答案在MVC 4中创建- 多对多关系和复选框但是,我真的很想看到它如何扩展到编辑和删除function以及此解决方案中的其他一些合作伙伴。 有人可以请说明如何在Edit控制器方法中填充ClassificationSelectViewModel以获取“已选中”和“未选中”值吗? 这是一个Matt Flowers问题,也将解决我的问题。
以下是此答案的延续, 该答案描述了为实体Subscription
和Company.
之间具有多对多关系的模型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; } }
SubscriptionEditViewModel
是SubscriptionCreateViewModel
加上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"); }