使用Entity Framework Core从Newtonsoft JsonSerializer自我引用循环

我遇到了错误:

JsonSerializationException:为类型为“Project.Models.Subject”的属性“Subject”检测到自引用循环。 路径’数据[0]。总计’。

当我使用由IEnumerable模型填充的dataGrid加载View时,会发生这种情况。 Grid是一个绑定到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中填充的,该控制器使用此function从存储库中提取数据:

 public async Task<IEnumerable> 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

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

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(); 

    该方法具有仅序列化所需数据的优点。 它与DevExtreme的DataSourceLoader兼容:

     return DataSourceLoader.Load(minimallyNecessarySet, loadOptions);