.NET Core中如何更新List<T>对象元素而非新增行
问题解决方法
核心问题分析
- 视图未提交主键值:你用
@Html.DisplayFor展示DefectId,但这个助手只会生成纯文本,不会生成带name属性的表单控件,导致提交到控制器时,每个Defect对象的DefectId都是默认值(比如0)。EF Core会把主键为默认值的实体判定为新实体,执行新增操作。 - 控制器逻辑错误:不管实体是已存在还是新创建的,你都调用
db.Defects.Add(i),这个方法始终会把实体标记为待新增状态。
第一步:修改视图,确保主键被提交
在展示DefectId的<td>里添加隐藏字段,让表单提交时带上主键值:
<td> @Html.DisplayFor(a => a[i].DefectId) @Html.HiddenFor(a => a[i].DefectId) <!-- 新增这行,提交主键值 --> </td>
如果JobId、DefectCreatedDate、DefectCreatedBy这些字段需要完整回传(即使不可修改),也可以给它们添加对应的隐藏字段,保证模型绑定的完整性。
第二步:修改控制器逻辑,区分新增与更新
方案一:查询现有实体后更新(推荐,更安全)
先从数据库获取对应实体,再修改需要更新的属性,EF会自动跟踪变化:
[HttpPost] public IActionResult Defectlist(List<Defect> model) { if (ModelState.IsValid) { foreach(var item in model) { var existingDefect = db.Defects.FirstOrDefault(d => d.DefectId == item.DefectId); if (existingDefect != null) { // 只更新需要修改的属性,这里以ProjectId为例 existingDefect.ProjectId = item.ProjectId; } // 如需支持新增,可保留以下逻辑 else { db.Defects.Add(item); } } db.SaveChanges(); TempData["SM"] = "任务已更新"; } return RedirectToAction("Defectlist"); }
方案二:直接设置实体状态(适合确定无新增的场景)
如果确定提交的都是已存在的实体,可直接标记实体为修改状态:
[HttpPost] public IActionResult Defectlist(List<Defect> model) { if (ModelState.IsValid) { foreach(var item in model) { db.Defects.Attach(item); // 标记整个实体为修改状态,或单独标记特定属性 db.Entry(item).Property(d => d.ProjectId).IsModified = true; } db.SaveChanges(); TempData["SM"] = "任务已更新"; } return RedirectToAction("Defectlist"); }
内容的提问来源于stack exchange,提问作者Rezo
相关产品推荐
相关产品推荐

