Self referencing loop from Newtonsoft JsonSerializer using Entity Framework Core

Val*_*tor 1 c# json.net devextreme entity-framework-core asp.net-core-mvc

I've encountered the error:

JsonSerializationException: Self referencing loop detected for property 'Subject' with type 'Project.Models.Subject'. Path 'data[0].Totals'.

It occurs when I load a View with a dataGrid populated by an IEnumerable<Subject> model. The Grid is a DevExtreme DataGrid bound to the View's model like this:

@(Html.DevExtreme().DataGrid()
    .DataSource(Model)
    .Paging(paging =>
    {
        paging.Enabled(true);
        paging.PageIndex(0);
        paging.PageSize(20);
    })
    .Columns(columns =>
    {
        columns.Add().DataField("SubjectId");
        ... other fields
    })
)
Run Code Online (Sandbox Code Playgroud)

Which is populated from a Controller that pulls data from a Repository with this function:

public async Task<IEnumerable<Subject>> GetSubjectsAsync()
        {
            return await _context.Subject.ToListAsync();
        }
Run Code Online (Sandbox Code Playgroud)

The Subject table has a 1:1 relationship with Totals with Totals having a foreign key reference to Subject. The Models in the project look like this (generated from Scaffold-DbContext):

public partial class Subject
    {
        public Guid SubjectId { get; set; }
        public virtual Totals Totals { get; set; }
    }

public partial class Totals
    {
        public Guid TotalsId { get; set; }
        public virtual Subject Subject { get; set; }
    }
Run Code Online (Sandbox Code Playgroud)

Since the 2 objects reference eachother it causes a loop when serializing it. To correct this I added this config to my Startup.ConfigureServices method:

services.AddMvc()
                .AddJsonOptions(x => x.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore);
Run Code Online (Sandbox Code Playgroud)

Which I got from this answer: /sf/answers/2835102511/

However this doesn't fix the problem and its still causing an error when I load a view that involves Subjects. Adding [JsonIgnore] to the Subject property of Totals fixes the problem, but I don't want to have to add that to every child property in my models and have to redo it whenever I update my models from the db.

ama*_*nov 5

JSON 序列化期间自引用循环的问题与 EFCore 如何加载相关数据 ( docs ) 相关。加载集合时,相关实体可能会或可能不会自动填充,具体取决于这些对象之前是否已加载。这称为导航属性的自动修复。或者,它们可以通过.Include().

每当您获得要序列化的实体的自引用图时,有几种选择:

  • Newtonsoft.Json.ReferenceLoopHandling.Ignore官方推荐)。它可以工作,但如果自引用发生在层次结构的深处,仍然会导致序列化过多的数据。

  • [JsonIgnore]导航属性上的属性。正如您所指出的,重新生成模型类时,属性会消失。因此,它们的使用可能不方便。

  • (最佳选择)预先选择属性子集:

    var minimallyNecessarySet= _nwind.Products.Select(p => new {
        p.ProductID,
        p.ProductName,
        p.UnitPrice,
        p.CategoryID
    });
    
    return minimallyNecessarySet.ToList();
    
    Run Code Online (Sandbox Code Playgroud)

    这种方法的优点是仅序列化所需的数据。它与 DevExtreme 兼容DataSourceLoader

    return DataSourceLoader.Load(minimallyNecessarySet, loadOptions);
    
    Run Code Online (Sandbox Code Playgroud)