ASP.NET Core 8 MVC更新客户端实体时出现DbUpdateConcurrencyException异常(Client ID传值为0)求助
兄弟,我一眼就揪出问题所在了——你的更新表单完全没把Client的ID传递到后端!这就是为啥调试时看到ID是0,进而触发DbUpdateConcurrencyException的根本原因:数据库里根本不存在ID为0的客户端记录,EF Core尝试更新0条记录,自然就抛出这个异常了。
问题根源分析
ASP.NET MVC的模型绑定是靠表单提交的字段来填充模型属性的。你现在的UpdateClient.cshtml里只放了CompanyName、BranchName这些业务字段,但完全漏掉了Client的主键ID字段。当表单提交时,模型绑定器找不到ID的值,就会给它赋默认值0,后端用这个ID去更新,数据库肯定找不到对应记录,直接触发异常。
你说产品模块能正常工作,大概率是因为产品的更新表单里加了Product ID的隐藏字段,所以ID能正确传递到后端。
具体解决步骤
1. 在表单中添加隐藏的ID字段
在UpdateClient.cshtml的<form>标签内部最上方,新增一个隐藏的ID输入框,让ASP.NET MVC能正确绑定到Client模型的ID属性:
<form asp-action="UpdateClient" asp-controller="Admin" method="post"> <!-- 新增隐藏ID字段,确保ID能被传递到后端 --> <input asp-for="Id" type="hidden" /> <!-- 以下是原有的表单字段 --> <div class="row"> <div class="col-4 mb-3"> <label asp-for="CompanyName">Company</label> <input asp-for="CompanyName" class="form-control" /> <span class="help-block text-danger" asp-validation-for="CompanyName"></span> </div> <!-- 其他原有字段省略... --> </div> </form>
这样表单提交时,ID就会和其他字段一起被传递到后端,模型绑定器就能正确填充Client的ID属性了。
2. 修复Repository中的异步方法错误
你的ClientRepository.cs里的UpdateClient方法有个小bug:方法是void但使用了await,这会导致编译错误,得改成async Task:
public async Task UpdateClient(Models.Client client) { _dbContext.Entry(client).State = EntityState.Modified; await _dbContext.SaveChangesAsync(); }
同时,Controller里也要记得await这个方法:
[HttpPost] [ValidateAntiForgeryToken] public async Task<IActionResult> UpdateClient(Client client) { // 建议先验证模型有效性,避免无效请求到数据库 if (!ModelState.IsValid) { return View(client); } await _clientRepository.UpdateClient(client); return RedirectToAction("Dashboard", "Admin"); }
3. 验证Client模型的主键配置
确保你的Client模型的ID属性是正确配置的主键,比如:
public class Client { public int Id { get; set; } // 按EF Core约定,命名为Id的字段默认是主键,或者可以添加[Key]特性明确标记 public string CompanyName { get; set; } // 其他属性... }
这样模型绑定器才能正确识别并绑定这个主键字段。
总结
核心问题就是表单缺失了Client的ID字段,导致后端无法定位到要更新的数据库记录。加上隐藏的ID字段后,这个问题应该就能解决。另外,记得修复异步方法的小问题,以及添加模型验证,让代码更健壮。
备注:内容来源于stack exchange,提问作者DonDavid12

