ASP.NET Core MVC中如何使用ViewModel更新三张关联表数据
ASP.NET Core MVC 多关联表学生信息更新功能实现方案
一、前置调整(解决编辑页数据回显问题)
首先确认三张表的外键关联关系正常:CurrentYearStudent关联StudentId,Student关联ParentId,仅通过传入的StudentId即可完成三张表的关联查询,无需修改列表页的编辑按钮传参逻辑。
编辑视图(UpdateStudent.cshtml)必须添加三个表主键的隐藏域绑定,避免POST时丢失主键无法定位存量数据:
@model StudentParentViewModel <!-- 其他表单字段 --> <input type="hidden" asp-for="ParentId" /> <input type="hidden" asp-for="StudentId" /> <input type="hidden" asp-for="CurrentYearStudentId" />
二、GET 版 UpdateStudent 动作实现
作用是根据传入的StudentId查询关联数据,填充ViewModel后返回编辑页:
public async Task<IActionResult> UpdateStudent(int studentId) { // 关联查询三张表的存量数据 var studentInfo = await _context.Students .Include(s => s.Parent) .Include(s => s.CurrentYearStudent) .FirstOrDefaultAsync(s => s.Id == studentId); if (studentInfo == null) { return NotFound(); } // 映射实体数据到ViewModel var viewModel = new StudentParentViewModel { // Parent表字段赋值 ParentId = studentInfo.Parent.Id, ParentName = studentInfo.Parent.Name, ParentContact = studentInfo.Parent.Contact, // Student表字段赋值 StudentId = studentInfo.Id, StudentName = studentInfo.Name, StudentBirthday = studentInfo.Birthday, // CurrentYearStudent表字段赋值 CurrentYearStudentId = studentInfo.CurrentYearStudent.Id, Grade = studentInfo.CurrentYearStudent.Grade, ClassNum = studentInfo.CurrentYearStudent.ClassNum }; return View(viewModel); }
三、POST 版 UpdateStudent 动作实现
加入事务控制保证三张表更新的一致性,避免部分更新成功导致数据异常:
[HttpPost] [ValidateAntiForgeryToken] public async Task<IActionResult> UpdateStudent(StudentParentViewModel viewModel) { if (!ModelState.IsValid) { return View(viewModel); } // 开启事务 using var transaction = await _context.Database.BeginTransactionAsync(); try { // 1. 更新Parent表数据 var parent = await _context.Parents.FindAsync(viewModel.ParentId); if (parent != null) { parent.Name = viewModel.ParentName; parent.Contact = viewModel.ParentContact; _context.Parents.Update(parent); await _context.SaveChangesAsync(); } // 2. 更新Student表数据 var student = await _context.Students.FindAsync(viewModel.StudentId); if (student != null) { student.Name = viewModel.StudentName; student.Birthday = viewModel.StudentBirthday; student.ParentId = viewModel.ParentId; _context.Students.Update(student); await _context.SaveChangesAsync(); } // 3. 更新CurrentYearStudent表数据 var cyStudent = await _context.CurrentYearStudents.FindAsync(viewModel.CurrentYearStudentId); if (cyStudent != null) { cyStudent.StudentId = viewModel.StudentId; cyStudent.Grade = viewModel.Grade; cyStudent.ClassNum = viewModel.ClassNum; _context.CurrentYearStudents.Update(cyStudent); await _context.SaveChangesAsync(); } // 提交事务 await transaction.CommitAsync(); return RedirectToAction(nameof(ViewStudents)); } catch (Exception ex) { // 更新失败回滚事务 await transaction.RollbackAsync(); ModelState.AddModelError(string.Empty, $"更新失败:{ex.Message}"); return View(viewModel); } }
四、异常问题排查点
- 若GET查询时关联表数据为空,检查EF Core的外键配置是否正确,是否开启了延迟加载
- 若POST时出现主键冲突,确认没有直接将ViewModel转为实体对象直接插入,必须先查询存量实体再更新字段
- 若字段更新不生效,检查ViewModel的字段名是否和实体字段名对应,表单绑定是否正常
内容的提问来源于stack exchange,提问作者Cameron Lodge
相关产品推荐
相关产品推荐

