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

EF Core 6未用Include却默认加载关联实体致JSON循环引用错误求助

问题分析与解决方案

为什么没加Include却自动加载了导航属性?

这是因为EF Core的延迟加载被启用了。当满足以下两个条件时,EF Core会自动触发延迟加载:

  • 实体类的导航属性(比如CreatedBy、AssetsCategoryCreatedList)被声明为virtual
  • 项目中启用了延迟加载代理(比如在AddDbContext时调用了.UseLazyLoadingProxies(),或者安装了Microsoft.EntityFrameworkCore.Proxies包)

当API序列化查询结果时,会访问到CreatedBy属性,触发延迟加载加载对应的Users实体;接着序列化Users时又访问到AssetsCategoryCreatedList,再次触发延迟加载加载关联的AssetsCategoryMaster集合,如此循环往复,就会出现JSON序列化的循环引用错误。


解决步骤

1. 关闭不必要的延迟加载

根据你的需求,有两种方式可以阻止自动加载导航属性:

  • 方式一:禁用延迟加载代理
    在Program.cs的数据库上下文配置中,移除或关闭UseLazyLoadingProxies:

    builder.Services.AddDbContext<YourDbContext>(options =>
        options.UseSqlServer(builder.Configuration.GetConnectionString("YourConnString"))
               .UseLazyLoadingProxies(false)); // 显式关闭,或者直接去掉.UseLazyLoadingProxies()
    
  • 方式二:将导航属性改为非virtual
    修改实体类的导航属性,去掉virtual关键字,EF Core就不会为这些属性生成延迟加载代理:

    // AssetsCategoryMaster类
    public Users CreatedBy { get; set; } // 去掉virtual
    
    // Users类
    public ICollection<AssetsCategoryMaster> AssetsCategoryCreatedList { get; set; } // 去掉virtual
    

2. 解决JSON循环引用问题

即使关闭了延迟加载,为了避免后续其他场景出现类似问题,建议配置JSON序列化忽略循环引用:
在Program.cs中添加JSON序列化选项配置:

builder.Services.AddControllers()
    .AddJsonOptions(options =>
    {
        // 忽略循环引用,序列化时遇到循环会自动跳过
        options.JsonSerializerOptions.ReferenceHandler = ReferenceHandler.IgnoreCycles;
        // 可选:如果需要保留引用关系,可以用ReferenceHandler.Preserve,会生成$id等标识字段
        // options.JsonSerializerOptions.ReferenceHandler = ReferenceHandler.Preserve;
    });

3. 推荐使用DTO(数据传输对象)

更规范的做法是创建DTO类,只包含API需要返回的字段,避免直接序列化实体类。比如:

public class AssetsCategoryDto
{
    public int Id { get; set; }
    public string AssetCategoryName { get; set; }
    // 只包含需要的CreatedBy信息,比如用户名
    public string CreatedByUserName { get; set; }
    // 不要包含双向导航的集合属性
}

查询时将实体映射到DTO返回:

var assetCategoryList = await _context.Set<AssetsCategoryMaster>()
    .Where(p => !p.IsDeleted)
    .Select(p => new AssetsCategoryDto
    {
        Id = p.Id,
        AssetCategoryName = p.AssetCategoryName,
        CreatedByUserName = p.CreatedBy.UserName
    })
    .ToListAsync();
return Ok(assetCategoryList);

这种方式不仅能彻底解决循环引用问题,还能减少数据传输量,提升API安全性。


内容的提问来源于stack exchange,提问作者Suresh M

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.09 02:25:21