ASP.NET Core如何传递含关联数据的实体并保留集合?
解决ASP.NET Core表单提交后多对多集合为空的问题
问题原因
<input asp-for="CrewMembers" hidden />无法传递集合数据,因为默认模型绑定无法通过单个隐藏字段解析复杂的集合类型,导致提交后CrewMembers集合为空。
可行解决方案
1. 逐个渲染集合元素的主键到隐藏字段
在视图中循环遍历CrewMembers集合,为每个成员的主键生成独立的隐藏字段,让模型绑定能正确识别集合结构:
<div class="col-md-7"> <form method="post" enctype="multipart/form-data"> <input asp-for="ProjectId" hidden /> @for (int i = 0; i < Model.CrewMembers.Count; i++) { <input asp-for="CrewMembers[i].CrewMemberId" hidden /> <!-- 若需要传递集合中其他属性,可添加对应的隐藏字段 --> } ... <button type="submit">Update</button> </form> </div>
提交后,Project对象的CrewMembers集合会包含带有主键的成员实例。
2. 从数据库重新加载集合(推荐方案)
不依赖视图传递集合,而是在POST方法中通过ProjectId重新查询数据库获取完整的对象(包含集合),再将视图提交的属性赋值过去。这种方式更安全,避免前端篡改数据:
//POST [HttpPost] [ValidateAntiForgeryToken] public IActionResult Modify(Project submittedObj) { if (!ModelState.IsValid) { return View(submittedObj); } // 从数据库加载包含集合的完整项目对象 var existingProject = _db.Projects .Include(c => c.CrewMembers) .FirstOrDefault(p => p.ProjectId == submittedObj.ProjectId); if (existingProject == null) { return NotFound(); } // 更新非集合类属性 _db.Entry(existingProject).CurrentValues.SetValues(submittedObj); // 若页面允许修改成员集合,需在此处处理集合变更(比如对比选中的成员ID,更新关联) // 示例:清空现有集合并添加选中成员 // existingProject.CrewMembers.Clear(); // var selectedCrewIds = Request.Form["SelectedCrewIds"].ToString().Split(',').Select(int.Parse); // foreach (var id in selectedCrewIds) // { // var crew = _db.CrewMembers.Find(id); // if (crew != null) existingProject.CrewMembers.Add(crew); // } _db.SaveChanges(); return RedirectToAction("Index"); }
3. 传递集合ID拼接字符串
将所有成员的主键拼接成字符串通过隐藏字段传递,在POST方法中拆分并重新加载集合:
- 视图代码:
<input type="hidden" name="CrewMemberIds" value="@string.Join(",", Model.CrewMembers.Select(c => c.CrewMemberId))" />
- POST方法代码:
[HttpPost] [ValidateAntiForgeryToken] public IActionResult Modify(Project obj, string crewMemberIds) { if (!string.IsNullOrEmpty(crewMemberIds)) { var ids = crewMemberIds.Split(',').Select(int.Parse); obj.CrewMembers = _db.CrewMembers.Where(c => ids.Contains(c.CrewMemberId)).ToList(); } // 建议结合方案2,使用数据库现有对象更新,避免直接Update导致的EF状态问题 var existing = _db.Projects.Find(obj.ProjectId); _db.Entry(existing).CurrentValues.SetValues(obj); _db.SaveChanges(); return RedirectToAction("Index"); }
内容的提问来源于stack exchange,提问作者Remo Pini
相关产品推荐
相关产品推荐

