You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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; 
}

问题原因

  1. IdPaciente为0的问题:页面提交的Familiar模型中IdPaciente未被正确绑定(大概率是表单未包含该字段),导致值为默认的0;且更新后直接使用原模型的IdPaciente跳转,未获取数据库中更新后的实体值。
  2. 变更未生效+空引用异常:
    • 多次调用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.24 18:57:17