Json的实体框架核心忽略ReferenceLoop-父子级

时间:2018-12-18 04:38:22

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

我的实体类具有父子关系,但是在使用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异常 Stackoverflow exception

我尝试使用忽略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

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

Department Seed Data

从种子数据来看,最大子级只有3个层级的深度,并且没有循环释放为无限循环。

  • A> B> C

因此我们在此种子数据中看不到A> B>无限循环。

此后,我们可以使用dotnet-httprepl进行调试,结果应该相同。 StackOverFlow

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

https://github.com/wangkanai/Organization/tree/bases/refactor

因此,只需enable get all departments,看看实体框架会返回什么;

Department with no parent as root departments

但这会为http-repl产生json序列化错误,可能是由于swagger ui json http://localhost:56739/swagger/v1/swagger.json

Stackoverflow by enabling get all

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; }
}

仍然产生相同的错误

Evening ignore the parent

所以现在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; }
}

get all departments but without the children

2 个答案:

答案 0 :(得分:0)

我很惊讶它抛出 异常,因为通常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; }
}

答案 1 :(得分:0)

我认为您无需转换DTO即可获取json格式,因为您拥有EF Code的第一个模型,我可以看到

    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上进行测试,但是让我知道代码是否存在问题。