请求协助基于现有MVC Create视图及EF实现Edit视图
太棒了,既然Create视图已经搞定,那Edit功能就水到渠成了!咱们主要要解决数据回显、联动下拉的选中状态保留和EF的实体更新这几个核心点,下面一步步来实现:
1. 控制器的GET Edit方法(加载待修改数据)
首先要根据联系人ID从数据库取出实体,映射到你的CountryStateContactViewModel,同时加载对应的国家/州列表并设置选中值:
public async Task<IActionResult> Edit(int? id) { if (id == null) { return NotFound(); } // 取出联系人,顺便关联加载State和Country(避免懒加载问题) var contact = await _context.Contacts .Include(c => c.State) .ThenInclude(s => s.Country) .FirstOrDefaultAsync(c => c.ContactId == id); if (contact == null) { return NotFound(); } // 映射到ViewModel var viewModel = new CountryStateContactViewModel { ContactId = contact.ContactId, Name = contact.Name, Email = contact.Email, Phone = contact.Phone, // 填充其他联系人字段... SelectedCountryId = contact.State.CountryId, SelectedStateId = contact.StateId }; // 加载国家下拉列表 viewModel.CountryList = new SelectList(await _context.Countries.ToListAsync(), "CountryId", "CountryName"); // 根据选中的国家加载对应的州列表 viewModel.StateList = new SelectList( await _context.States.Where(s => s.CountryId == viewModel.SelectedCountryId).ToListAsync(), "StateId", "StateName" ); return View(viewModel); }
2. 控制器的POST Edit方法(保存修改)
处理表单提交,验证模型后更新实体,还要处理验证失败时的下拉列表重新加载:
[HttpPost] [ValidateAntiForgeryToken] public async Task<IActionResult> Edit(int id, CountryStateContactViewModel viewModel) { if (id != viewModel.ContactId) { return NotFound(); } if (ModelState.IsValid) { try { // 取出要更新的实体 var contact = await _context.Contacts.FindAsync(id); if (contact == null) { return NotFound(); } // 更新实体字段 contact.Name = viewModel.Name; contact.Email = viewModel.Email; contact.Phone = viewModel.Phone; // 更新其他字段... contact.StateId = viewModel.SelectedStateId; _context.Update(contact); await _context.SaveChangesAsync(); } catch (DbUpdateConcurrencyException) { if (!ContactExists(viewModel.ContactId)) { return NotFound(); } else { throw; } } return RedirectToAction(nameof(Index)); } // 验证失败时,重新加载下拉列表并保留用户选择的选项 viewModel.CountryList = new SelectList( await _context.Countries.ToListAsync(), "CountryId", "CountryName", viewModel.SelectedCountryId ); viewModel.StateList = new SelectList( await _context.States.Where(s => s.CountryId == viewModel.SelectedCountryId).ToListAsync(), "StateId", "StateName", viewModel.SelectedStateId ); return View(viewModel); } // 辅助方法:检查联系人是否存在 private bool ContactExists(int id) { return _context.Contacts.Any(e => e.ContactId == id); }
3. Edit视图的编写(复用联动逻辑+回显)
大部分代码可以复用Create视图的结构,只需要确保表单绑定正确,且下拉框能自动选中对应值:
@model CountryStateContactViewModel @{ ViewData["Title"] = "Edit Contact"; } <h1>Edit Contact</h1> <hr /> <div class="row"> <div class="col-md-4"> <form asp-action="Edit"> <div asp-validation-summary="ModelOnly" class="text-danger"></div> <!-- 隐藏ID字段,确保提交时能匹配到要修改的实体 --> <input type="hidden" asp-for="ContactId" /> <!-- 联系人基本信息字段 --> <div class="form-group"> <label asp-for="Name" class="control-label"></label> <input asp-for="Name" class="form-control" /> <span asp-validation-for="Name" class="text-danger"></span> </div> <div class="form-group"> <label asp-for="Email" class="control-label"></label> <input asp-for="Email" class="form-control" /> <span asp-validation-for="Email" class="text-danger"></span> </div> <!-- 其他联系人字段... --> <!-- 联动下拉框 --> <div class="form-group"> <label asp-for="SelectedCountryId" class="control-label"></label> <select asp-for="SelectedCountryId" asp-items="@Model.CountryList" class="form-control"> <option value="">-- Select Country --</option> </select> <span asp-validation-for="SelectedCountryId" class="text-danger"></span> </div> <div class="form-group"> <label asp-for="SelectedStateId" class="control-label"></label> <select asp-for="SelectedStateId" asp-items="@Model.StateList" class="form-control"> <option value="">-- Select State --</option> </select> <span asp-validation-for="SelectedStateId" class="text-danger"></span> </div> <div class="form-group"> <input type="submit" value="Save Changes" class="btn btn-primary" /> </div> </form> </div> </div> <div> <a asp-action="Index">Back to Contacts List</a> </div> @section Scripts { @{await Html.RenderPartialAsync("_ValidationScriptsPartial");} <!-- 复用Create视图的联动JS逻辑 --> <script> $(document).ready(function () { $("#SelectedCountryId").change(function () { var countryId = $(this).val(); // 这里的路由要和你Create视图里的一致 $.get("/Contacts/GetStatesByCountryId?countryId=" + countryId, function (data) { $("#SelectedStateId").empty(); $.each(data, function (index, item) { $("#SelectedStateId").append('<option value="' + item.stateId + '">' + item.stateName + '</option>'); }); }); }); }); </script> }
4. 关键注意事项
- 确保你的
CountryStateContactViewModel包含ContactId字段,用于匹配要修改的实体 - 如果Create视图里已经有
GetStatesByCountryId这个Action(返回对应国家的州列表),直接复用即可,不需要重复写 - 下拉框的
asp-for会自动匹配ViewModel里的SelectedCountryId和SelectedStateId值,实现选中状态回显 - 并发异常处理(
DbUpdateConcurrencyException)是可选但推荐的,防止多人同时修改同一数据导致冲突
内容的提问来源于stack exchange,提问作者Sven Nenadić
相关产品推荐
相关产品推荐

