【问题标题】:Entity Framework Core to Json Ignore ReferenceLoop - Parent Child实体框架核心到 Json 忽略 ReferenceLoop - 父子
【发布时间】:2018-12-18 04:38:21
【问题描述】:

我有具有父子关系的实体类,使用 newtonsoft json.net 序列化为 json 时遇到问题

public class Department
{        
    [Key]
    public int DepartmentId { get; set; }          
    public int? ParentId { get; set; }       
    public Department Parent { get; set; }          
    public ICollection<Department> Children { get; set; }
    public string Title { get; set; }
}

虽然我期待这样的 json 格式。

[
  {
    "departmentId": 1,   
    "title":        "Finance",
    "children": [
      {
        "departmentId": 2,        
        "title":        "Accounting",
        "children": [
          {
            "departmentId": 3,            
            "title":        "Payable"
          }
        ]
      }
    ]
  }
]

但结果我从 http-repl 得到了这个 Stackoverflow 异常

我尝试使用 Ignore ReferenceLooping,这并不能解决我遇到的 stackoverflow 问题

services.AddMvc()
    .AddJsonOptions(options => {
       options.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;
    })

这里是控制器,如果你问的话;

//GET: api/Department
[HttpGet]
public async Task<ActionResult<IEnumerable<Department>>> GetDepartments()
{
    var result = await _context.Departments
        .Include(department => department.Children)
        .Where(department => department.ParentId == null)
        .ToListAsync();
    return Ok(result);
}

我已经尝试过数据传输对象 (DTO) 仍然无法正常工作。

2018 年 12 月 29 日更新

让我们正确设置,您可以在https://github.com/wangkanai/Organization/tree/base 克隆基础项目。然后就可以在以下路径中添加数据库src\Organization.WebApi

dotnet ef migrations add init
dotnet ef database update

这将为您提供部门的种子数据以及以下数据

从种子数据中,我们将只有 3 层深度的最大子节点,并且没有循环释放作为无限循环。

  • A > B > C

所以我们在这个种子数据中看不到 A > B > 无限循环。

在此之后,我们可以使用dotnet-httprepl 进行调试,我们应该得到相同的结果。

现在让部门控制器中的comment out all methods 限制错误范围。然后我们启动并运行 http-repl。

所以让enable get all departments 看看实体框架返回什么;

但这会产生 http-repl 的 json 序列化错误,可能来自 swagger ui json http://localhost:56739/swagger/v1/swagger.json

Lets add \[JsonIgnore\] to the Site & Parent 然后重新运行 http-repl

public class Department
{        
    [Key]
    public int DepartmentId { get; set; }
    [JsonIgnore]
    public int SiteId { get; set; }
    [JsonIgnore]
    public Site Site { get; set; }
    [JsonIgnore]
    public int? ParentId { get; set; }
    [JsonIgnore]
    public Department Parent { get; set; }          
    public ICollection<Department> Children { get; set; }
    public string Title { get; set; }
}

仍然会产生同样的错误

所以现在let Ignore all relationship 序列化 json 看看能不能得到所有部门。但是这个生产部门没有它的孩子,这并不是我们期望的正确结果。

public class Department
{        
    [Key]
    public int DepartmentId { get; set; }
    [JsonIgnore]
    public int SiteId { get; set; }
    [JsonIgnore]
    public Site Site { get; set; }
    [JsonIgnore]
    public int? ParentId { get; set; }
    [JsonIgnore]
    public Department Parent { get; set; }
    [JsonIgnore]
    public ICollection<Department> Children { get; set; }
    public string Title { get; set; }
}

【问题讨论】:

  • 请显示您的控制器方法代码!
  • 你用过 AutoMapper 吗?
  • @AliTooshmalani 是的,我试过 AutoMapper
  • @SarinNaWangkanai 请检查我的答案,让我知道它是否有效!如果没有,请告诉我问题所在!

标签: c# json serialization asp.net-core entity-framework-core


【解决方案1】:

我很惊讶它会抛出 that 异常,因为通常 Json.NET 会在 StackOverflow 发生之前捕获循环引用。但仍有可能是循环引用杀死了它。 (它试图序列化Parent,然后查看其中的Children,然后查看每个Parent,等等)

你可以修改你的模型来告诉序列化忽略Parent

public class Department
{        
    [Key]
    public int DepartmentId { get; set; }          
    public int? ParentId { get; set; }
    [JsonIgnore]
    public Department Parent { get; set; }          
    public ICollection<Department> Children { get; set; }
    public string Title { get; set; }
}

【讨论】:

  • 是的,我试过 AutoMapper github.com/wangkanai/Organization/commit/…
  • Parent 上添加[JsonIgnore] 没有帮助,如果我在Children 上添加[JsonIgnore],那么它不会产生孩子。
  • 如果忽略Children 使其完整(但没有子级),这意味着您的Children 中有一个循环引用(一个部门的一个子级也是它自己的父级)。它甚至可以是几层深,例如:A -> B -> C -> A。这将导致它无限循环。
【解决方案2】:

我认为你不需要转换 DTO 来获取 json 格式,因为你有我可以看到的 EF Code first 模型

    public class Department
    {        
    [Key]
    public int DepartmentId { get; set; }          
    public int? ParentId { get; set; }       
    public Department Parent { get; set; }          
    public ICollection<Department> Children { get; set; }
    public string Title { get; set; }
    }

您可以直接从您的动作控制器返回 json 输出,如下所示。

     public class JsonDemoController : Controller  
     {  
        #region ActionControllers  

         /// <summary>  
        /// Get department data in Json Format  
        /// </summary>  
        /// <returns></returns> 

        public JsonResult GetDepartmentJsonData()  
        {  
            var departments= GetDepartments();  
            return Json(departments, JsonRequestBehavior.AllowGet);  
        }


        private List<Department> GetDepartments()  
        {  
            var departmentList = new List<Department>  
            {  
                new Department  
                {  
                    DepartmentId = 1,  
                    Title = "Finance",  
                    Children = childrenCollection
                }  

            };  

            return departmentList;  
        }     
     }  

我没有在 IDE 上测试过,但如果代码有任何问题,请告诉我。

【讨论】:

猜你喜欢
  • 1970-01-01
  • 2023-03-16
  • 2014-07-17
  • 2018-07-08
  • 1970-01-01
  • 2021-07-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多