Razor+ASP.NET Core+EF多实体更新异常:空引用及IdPaciente值异常
问题分析与解决方案
问题现象
- 同时更新
Familiar和Persona两个实体时,变更未生效 - 提交表单触发错误:
NullReferenceException: Object reference not set to an instance of an object
- 跳转链接中显示
IdPaciente = 0,而非实体原本的IdPaciente值
用户代码
Razor页面Post方法
public IActionResult OnPost() { if (!ModelState.IsValid) { return Page(); } repositorioFamiliar.Actualizar(Familiar); return RedirectToPage("/Familiares/DetalleFamiliar", new { IdPaciente = Familiar.IdPaciente }); }
实体更新方法
public FamiliaresPer Actualizar(FamiliaresPer familiar) { var familiarActualizar = (from f in _context.Familiars.Where(p => p.IdFamiliar == familiar.IdFamiliar) select f).FirstOrDefault(); if (familiarActualizar != null) { familiarActualizar.Correo = familiar.Correo; _context.Update(familiarActualizar); _context.SaveChanges(); } var personaActualizar = (from p in _context.Personas.Where(p => p.Id == familiar.IdPersona) select p).FirstOrDefault(); if (personaActualizar != null) { personaActualizar.Telefono = familiar.Telefono; _context.Update(personaActualizar); _context.SaveChanges(); } var familiares = from p in _context.Familiars from p1 in _context.Personas where p.IdPaciente == familiar.IdPaciente where p.IdPersona == p1.IdPersona select new FamiliaresPer() { IdFamiliar = p.IdFamiliar, IdPaciente = p.IdPaciente, IdPersona = p1.IdPersona, Id = p1.Id, Nombres = p1.Nombres, Apellidos = p1.Apellidos, Genero = p1.Genero, Telefono = p1.Telefono, Parentesco = p.Parentesco, Correo = p.Correo, }; FamiliaresPer familiaresPer = familiares.FirstOrDefault(); return familiaresPer; }
问题原因
- IdPaciente为0的问题:页面提交的
Familiar模型中IdPaciente未被正确绑定(大概率是表单未包含该字段),导致值为默认的0;且更新后直接使用原模型的IdPaciente跳转,未获取数据库中更新后的实体值。 - 变更未生效+空引用异常:
- 多次调用
SaveChanges()但未保证事务一致性,若其中一步出错会导致数据不一致;且Update()方法冗余——从上下文查询的实体已被跟踪,直接修改属性即可。 - 后续查询
familiares时,使用的familiar.IdPaciente是0,导致查询不到数据,返回null;若调用方未判空则触发空引用异常。
- 多次调用
解决方案
1. 修复跳转时IdPaciente的问题
- 先在表单中添加隐藏字段,确保
IdPaciente被正确绑定:<input type="hidden" asp-for="Familiar.IdPaciente" /> - 改用更新方法返回的实体进行跳转,同时增加空值判断:
public IActionResult OnPost() { if (!ModelState.IsValid) { return Page(); } var updatedFamiliar = repositorioFamiliar.Actualizar(Familiar); if(updatedFamiliar == null) { ModelState.AddModelError("", "无法找到要更新的亲属信息"); return Page(); } return RedirectToPage("/Familiares/DetalleFamiliar", new { IdPaciente = updatedFamiliar.IdPaciente }); }
2. 优化更新逻辑,确保变更生效
public FamiliaresPer Actualizar(FamiliaresPer familiar) { // 先验证关键ID有效性 if(familiar.IdFamiliar <=0 || familiar.IdPersona <=0 || familiar.IdPaciente <=0) { return null; } // 使用事务保证两个实体更新的一致性 using(var transaction = _context.Database.BeginTransaction()) { try { var familiarActualizar = _context.Familiars.FirstOrDefault(f => f.IdFamiliar == familiar.IdFamiliar); if (familiarActualizar != null) { familiarActualizar.Correo = familiar.Correo; // 无需调用Update,实体已被上下文跟踪 } var personaActualizar = _context.Personas.FirstOrDefault(p => p.Id == familiar.IdPersona); if (personaActualizar != null) { personaActualizar.Telefono = familiar.Telefono; // 无需调用Update } _context.SaveChanges(); transaction.Commit(); } catch(Exception) { transaction.Rollback(); return null; } } // 精准查询当前更新的实体,避免返回错误数据 var familiares = from p in _context.Familiars join p1 in _context.Personas on p.IdPersona equals p1.IdPersona where p.IdPaciente == familiar.IdPaciente && p.IdFamiliar == familiar.IdFamiliar select new FamiliaresPer() { IdFamiliar = p.IdFamiliar, IdPaciente = p.IdPaciente, IdPersona = p1.IdPersona, Id = p1.Id, Nombres = p1.Nombres, Apellidos = p1.Apellidos, Genero = p1.Genero, Telefono = p1.Telefono, Parentesco = p.Parentesco, Correo = p.Correo, }; return familiares.FirstOrDefault(); }
3. 额外注意事项
- 检查页面模型绑定的所有关键ID(
IdFamiliar、IdPersona、IdPaciente)是否都通过表单传递到后端。 - 所有
FirstOrDefault()调用后必须做空值判断,避免空引用异常。
内容的提问来源于stack exchange,提问作者Victor Alarcon
相关产品推荐
相关产品推荐

