EF Core - 为啥“无限”嵌套急切加载?

Posted

技术标签:

【中文标题】EF Core - 为啥“无限”嵌套急切加载?【英文标题】:EF Core - why 'infinate' nested eager loading?EF Core - 为什么“无限”嵌套急切加载? 【发布时间】:2021-01-26 06:29:07 【问题描述】:

我有两个实体之间的一对多关系:地图和地图节点。当我渴望用 Maps 加载 MapNodes(通过 Include())时,我得到 Map,我得到相关的 MapNodes,但在相关的 MapNodes 中,我也再次得到完整的父 Map。然后该地图(再次)具有关联的 MapNode,依此类推......

我需要将查询的内容限制在一个级别(即 MapNodes),而不是让预加载更深入。

[Table("maps")]
public partial class Maps

    public Maps()
    
        MapNodes = new HashSet<MapNodes>();
    

    <...>
    [InverseProperty("Map")]
    public virtual ICollection<MapNodes> MapNodes  get; set; 


[Table("map_nodes")]
public partial class MapNodes

    public MapNodes()
    
    

    <...>
    [Column("map_id", TypeName = "int(10) unsigned")]
    public uint MapId  get; set; 

    public Maps Map  get; set; 


当我执行以下查询时:

    var map = await context.Maps.Include( x => x.MapNodes).FirstOrDefaultAsync( x => x.Id == id);

我得到一个无限的急切加载:


    "id": 1063,
    "mapNodes": [
        
            "id": 25784,
            "mapId": 1063,
            "map": 
                "id": 1063,
                "mapNodes": [
                    
                        "id": 25784,
                        "mapId": 1063,
                        "map": 
                            "id": 1063,
                            "mapNodes": [
                        ...

【问题讨论】:

这称为Reference Loop HandlingSystem.Text.Json 尚不可用。但它在Microsoft.AspNetCore.Mvc.NewtonsoftJson 中可用在您的startup 中,您可以通过AddControllersWithViews().AddNewtonsoftJson()x.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore; 进行配置。 谢谢!你能发布一个解决方案吗?我会“接受”它。 如果您查询相关实体(使用Include),EF 生成的对象将始终包含循环引用。在将数据发送到客户端之前,创建一组类来表示平面数据(Response/DTO/ViewModel 对象)并将实体/模型对象映射到这些类,而不是直接发送查询结果,这是一个更好的选择。 【参考方案1】:

Microsoft 将 ASP.NET Core 3 中的 Microsoft.AspNetCore.Mvc.NewtonsoftJson 替换为他们自己的实现,即 System.Text.Json,但它还不支持 Reference Loop Handling 处理。

所以为了配置Reference Loop Handling,你需要为Microsoft.AspNetCore.Mvc.NewtonsoftJson添加nuget包,然后这样配置:

services.AddControllersWithViews().AddNewtonsoftJson(options => 
    options.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;
);

【讨论】:

以上是关于EF Core - 为啥“无限”嵌套急切加载?的主要内容,如果未能解决你的问题,请参考以下文章

EF Core,投影子集合急切加载

EF CTP5 - 强类型急切加载 - 如何包含嵌套导航属性?

.NET Core/EF Core 2.0 升级后急切加载“类型之间未定义强制运算符”

EF Core 5.0.4 - 从核心 3.1 升级后,通过 Include() 的急切加载不起作用

Entity Framework Core 2.0.1 急切加载所有嵌套的相关实体

为啥我的代码在执行时的初始嵌套 for 循环中进入无限循环?