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
相关产品推荐
相关产品推荐

