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

Blazor索引视图中一对多关联显示Clasificacion名称失败求助

问题描述

我是Blazor、EF和.NET Core的新手,定义了Mercancia和Clasificacion两个模型类,二者为一对多关联关系。希望在Mercancia的列表页面中显示关联的Clasificacion名称(而非ClasificacionId),但该功能无法正常工作。

模型定义

public partial class Mercancia
{
    public Mercancia()
    {
        AlmacenItems = new HashSet<AlmacenItem>();
        RecepcionItems = new HashSet<RecepcionItem>();
        ValeItems = new HashSet<ValeItem>();
    }

    public int Id { get; set; }
    public string Nombre { get; set; } = null!;
    public int ClasificacionId { get; set; }
    public string Codigo { get; set; } = null!;
    public string? Descripcion { get; set; }
    public string Um { get; set; } = null!;
    public virtual Clasificacion Clasificacion { get; set; } = null!;
}
public partial class Clasificacion
{
    public Clasificacion()
    {
        Mercancia = new HashSet<Mercancia>();
    }

    public int Id { get; set; }
    public string Nombre { get; set; } = null!;
    public string? Detalle { get; set; }

    public virtual ICollection<Mercancia> Mercancia { get; set; }
}

Mercancia控制器

[Route("api/[controller]")]
[ApiController]
public class MercanciaController : Controller
{
    private readonly IMercancias imercancias;
    public IActionResult Index()
    {            
        return View();
    }
    public MercanciaController(IMercancias imercancias)
    {
        this.imercancias = imercancias;
    }
    [HttpGet]
    public async Task<ActionResult<List<Mercancia>>> Get()
    {
        return await Task.FromResult(imercancias.Lista());
    }

    [HttpPost]
    public void Post(Mercancia mercancia)
    {
        imercancias.Adicionar(mercancia);
    }

    [HttpGet("{id}")]
    public IActionResult Get(int id)
    {
        Mercancia u = imercancias.Obtener(id);
        if (u != null)
        {
            return Ok(u);
        }
        return NotFound();
    }

    [HttpPut]
    public void Put(Mercancia merca)
    {
        imercancias.Editar(merca);
    }

    [HttpDelete("{id}")]
    public IActionResult Delete(int id)
    {
        imercancias.Eliminar(id);
        return Ok();
    }
}

服务实现

public interface IMercancias
{
    public List<Mercancia> Lista();

    public void Adicionar(Mercancia u);

    public void Editar(Mercancia u);

    public Mercancia Obtener(int id);

    public void Eliminar(int id);
}
public class GestionMercancias : IMercancias
{
    readonly RaicesDBContext context = new();
    public GestionMercancias(RaicesDBContext context)
    {
        this.context = context;
    }
    public void Editar(Mercancia u)
    {
        try
        {
            context.Entry(u).State = EntityState.Modified;
            context.SaveChanges();
        }
        catch (Exception ex)
        {
            throw new Exception(ex.ToString());
        }
    }

    public void Eliminar(int id)
    {
        try
        {
            Mercancia? u = context.Mercancias.Find(id);
            if (u != null)
            {
                context.Mercancias.Remove(u);
                context.SaveChanges();
            }
            else
            {
                throw new ArgumentNullException();
            }
        }
        catch (Exception ex)
        {
            throw new Exception(ex.ToString());
        }
    }

    public List<Mercancia> Lista()
    {
        try
        {
            return context.Mercancias.ToList();
        }
        catch (Exception ex)
        {
            throw new Exception(ex.ToString());
        }
    }

    public Mercancia Obtener(int id)
    {
        try
        {
            Mercancia? u = context.Mercancias.Find(id);
            if (u != null)
            {
                return u;
            }
            else
            {
                throw new ArgumentNullException();
            }
        }
        catch (Exception ex)
        {
            throw new Exception(ex.ToString());
        }
    }

    public void Adicionar(Mercancia u)
    {
        try
        {
            context.Mercancias.Add(u);
            context.SaveChanges();
        }
        catch (Exception ex)
        {
            throw new Exception(ex.ToString());
        }
    }
}

视图代码

@page "/mercancias"
@inject HttpClient client
@inject IJSRuntime js
<h3>Mercancías</h3>
<small>Adiciona mercancías.</small>
<div class="form-group">
    <a class="btn btn-success" href="mercancias/create"><i class="oi oi-plus"></i> Nuevo</a>
</div>
<br>
@if (mercancias == null)
{
    <text>Loading...</text>
}
else if (mercancias.Count == 0)
{
    <text>No Records Found.</text>
}
else
{
    <table class="table table-striped">
        <thead>
            <tr>
                <th>Id</th>
                <th>Mercancia</th>
                <th>Clasificacion</th>
                <th>Codigo</th>
                <th>UM</th>
                <th>Detalles</th>
                <th></th>
            </tr>
        </thead>
        <tbody>
            @foreach (Mercancia merc in mercancias)
            {
                <tr>
                    <td>@merc.Id</td>
                    <td>@merc.Nombre</td>
                    <td>@merc.Clasificacion.Nombre</td> **此处为问题所在**
                    <td>@merc.Um</td>
                    <td>@merc.Descripcion</td>
                    <td>
                        <a class="btn btn-success" href="mercancias/editar/@merc.Id">Edit</a>
                        <button class="btn btn-danger" @onclick="@(() => Delete(merc.Id))">Delete</button>
                    </td>
                </tr>
            }
        </tbody>
    </table>
}
@code {
    List<Mercancia> mercancias { get; set; }
    protected override async Task OnInitializedAsync()
    {
        mercancias = await client.GetFromJsonAsync<List<Mercancia>>("api/Mercancia");
    }
    async Task Delete(int Id)
    {
        var merca = mercancias.First(x => x.Id == Id);
        if (await js.InvokeAsync<bool>("confirm", $"Do you want to delete {merca.Nombre}'s ({merca.Id}) Record?"))
        {
            await client.DeleteAsync($"api/Mercancia/{Id}");
            await OnInitializedAsync();
        }
    }
}
解决方案

问题根源是EF没有加载关联的Clasificacion实体,导致API返回的Mercancia对象中Clasificacion属性为null,视图访问@merc.Clasificacion.Nombre时出现空引用错误。按以下步骤修复:

1. 显式加载关联实体(推荐)

修改GestionMercancias中的Lista()和Obtener()方法,使用Include显式包含关联的Clasificacion:

修改Lista方法

public List<Mercancia> Lista()
{
    try
    {
        // 添加Include加载关联的Clasificacion
        return context.Mercancias.Include(m => m.Clasificacion).ToList();
    }
    catch (Exception ex)
    {
        throw new Exception(ex.ToString());
    }
}

修改Obtener方法

public Mercancia Obtener(int id)
{
    try
    {
        // 使用Include加载关联实体,并用FirstOrDefault替代Find
        Mercancia? u = context.Mercancias.Include(m => m.Clasificacion).FirstOrDefault(m => m.Id == id);
        if (u != null)
        {
            return u;
        }
        else
        {
            throw new ArgumentNullException();
        }
    }
    catch (Exception ex)
    {
        throw new Exception(ex.ToString());
    }
}

2. 配置JSON序列化处理循环引用

由于Clasificacion和Mercancia是双向关联,序列化时会出现循环引用问题,需要在Program.cs(或Startup.cs)中配置JSON序列化选项:

builder.Services.AddControllers()
    .AddJsonOptions(options =>
    {
        // 忽略循环引用
        options.JsonSerializerOptions.ReferenceHandler = ReferenceHandler.IgnoreCycles;
        // 序列化时忽略null值(可选)
        options.JsonSerializerOptions.DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull;
    });

3. 视图添加空值保护(可选)

为了避免万一关联数据未加载时出现错误,可在视图中添加空值判断:

<td>@(merc.Clasificacion?.Nombre ?? "Sin clasificación")</td>

内容的提问来源于stack exchange,提问作者Roberto Vargas

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.20 09:33:32