Self referencing loop from Newtonsoft JsonSerializer using Entity Framework Core 使用Entity Framework Core时,从Newtonsoft JsonSerializer引发自引用循环。
Self referencing loop from Newtonsoft JsonSerializer using Entity Framework Core 使用Entity Framework Core时,从Newtonsoft JsonSerializer引发自引用循环。
我遇到了以下错误:
JsonSerializationException:检测到自引用循环'Property 'Subject' with type 'Project.Models.Subject'。路径'data[0].Totals'。
当我加载一个由IEnumerable
@(Html.DevExtreme().DataGrid() .DataSource(Model) .Paging(paging => { paging.Enabled(true); paging.PageIndex(0); paging.PageSize(20); }) .Columns(columns => { columns.Add().DataField("SubjectId"); ...其他字段 }) )
该视图从一个从存储库中获取数据的控制器填充,该控制器使用以下函数:
public async Task> 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; } }
由于这两个对象相互引用,导致在序列化时产生循环。为了解决这个问题,我在我的Startup.ConfigureServices方法中添加了以下配置:
services.AddMvc() .AddJsonOptions(x => x.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore);
我从这个答案中得到了这个配置:https://stackoverflow.com/a/40501464/7897176
然而,这并没有解决问题,当我加载涉及Subjects的视图时仍然会出错。将[JsonIgnore]添加到Totals的Subject属性可以解决这个问题,但是我不想在我的模型的每个子属性中都添加它,并且在从数据库更新模型时不想重复这样做。
在使用Entity Framework Core进行JSON序列化时,出现了自引用循环的问题。这个问题与EFCore加载相关数据的方式有关。当加载一个集合时,相关实体可能会自动填充,具体取决于这些对象是否已经被先前加载过。这被称为导航属性的自动修复。或者,可以通过`.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);
我发现,在使用这些DevExtreme组件时,选择只包含所需属性的子集方法是最好的方法。这些控件会序列化绑定给它们的整个对象,而不管它是否真正被使用,这可能导致服务器响应非常庞大。