c# - 使用 Entity Framework Core 来自 Newtonsoft JsonSerializer 的自引用循环

标签 c# json.net asp.net-core-mvc entity-framework-core devextreme

我遇到了错误:

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

当我加载一个 View ,其中的数据网格由 IEnumerable<Subject> 填充时,会发生这种情况模型。 Grid 是绑定(bind)到 View 模型的 DevExtreme DataGrid,如下所示:

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

它是从 Controller 填充的,该 Controller 使用此功能从存储库中提取数据:

public async Task<IEnumerable<Subject>> GetSubjectsAsync()
        {
            return await _context.Subject.ToListAsync();
        }

Subject 表与 Totals 具有 1:1 的关系,Totals 具有指向 Subject 的外键引用。项目中的模型如下所示(从 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; }
    }

由于这 2 个对象相互引用,因此在序列化时会导致循环。为了纠正这个问题,我将这个配置添加到我的 Startup.ConfigureServices 方法中:

services.AddMvc()
                .AddJsonOptions(x => x.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore);

我从这个答案中得到:https://stackoverflow.com/a/40501464/7897176

但是,这并不能解决问题,当我加载涉及主题的 View 时,它仍然会导致错误。添加[JsonIgnore]添加到 Totals 的 Subject 属性解决了这个问题,但我不想将它添加到我模型中的每个子属性,并且每当我从数据库更新我的模型时都必须重做。

最佳答案

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

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

  • Newtonsoft.Json.ReferenceLoopHandling.Ignore ( officially recommended )。它有效,但如果自引用发生在层次结构的深处,仍然会导致序列化过多的数据。

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

  • (最佳选择)预选一部分属性:

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

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

    return DataSourceLoader.Load(minimallyNecessarySet, loadOptions);
    

关于c# - 使用 Entity Framework Core 来自 Newtonsoft JsonSerializer 的自引用循环,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44555186/

相关文章:

c# - 通过 C# 代码避免 GridView 中的重复行

c# - 通过mvvmcross进行非线性导航

c# - 如何在第一个任务 RanToCompletion 之后等待

c# - 使用 JSON.NET 的序列化字段的顺序

c# - 通过 json.net 中的属性名称查找值?

c# - ASP.NET Web-api 核心 : Handling client connections problems and find conflicts

c# - JSON 数组到 ExpandoObject 通过 JSON.NET

visual-studio-2015 - 如何在 ASP.NET Core MVC 中添加 DefinitelyTyped

.net-core - 如何在 SkiaSharp 中将字节数组转换为 SKBitmap?

c# - aspnet 5 RESTful api ModelState.IsValid == true 即使值根据 DataAnnotations 无效