避免或控制 Entity Framework Core 中的循环引用 [英] Avoid or control circular references in Entity Framework Core

查看:29
本文介绍了避免或控制 Entity Framework Core 中的循环引用的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我真的已经完成了,但至少我想知道发生了什么.我们开始:

I really am done with this, but at least I want to know what's going on. Here we go:

我的项目是一个 ASP.NET Core Web 应用程序,带有 Code First Entity Framework Core 和一个 Angular 前端.

My project is an ASP.NET Core Web Application with Code First Entity Framework Core and an Angular frontend.

我想控制何时加载引用的对象.它们可能很有用,但它们也可以在前端创建带有内部错误的循环引用.(JSON 会无限长.)

I want to control when to load referenced objects. They can be useful, but they can also create circular references with internal errors on the frontend. (JSON would be infinitely long.)

型号:

class Book {
   public virtual ICollection<Page> Pages { get; set; }
   ...simple properties
}

class Page {
   public virtual Book Book { get; set; }
   ...simple properties
}

在这个例子中,books 中的每一本书都会有一个空/空的 Pages 列表.

In this example, every book from books will have an empty/null Pages list.

using (var context = new MoneyStatsContext())
{
   var books = context.Books.Where(rule => rule.State == 1).ToList();
}

在这个例子中,Pages 列表不为空,并且每个 Page 都会设置它的 Book 属性.从而创建循环引用.

In this example, the Pages lists are not null, and every Page will have it's Book property set. Thus creating a circular reference.

using (var context = new MoneyStatsContext())
{
   var books = context.Books.Where(rule => rule.State == 1).Include(x => x.Pages).ToList();
}

如何避免循环引用?除了创建新模型并手动指定每个属性之外,我真的没有其他(更简单的)选择吗?

How do I avoid the circular reference? Do I really have no other (simpler) choice than creating a new model and manually specifying each property?

.Select(new Book() {
   ...setting each property by hand
}

我发现的无效解决方案:

  • 尝试将此设置为 false 和 true.似乎没有任何改变.
public MyContext()
{
   this.ChangeTracker.LazyLoadingEnabled = false;
}


  • 尝试在 Startup.cs 中指定此项,但 options 没有 SerializerSettings 属性.

    • Tried specifying this in Startup.cs, but options doesn't have a SerializerSettings property.
    • services.AddMvc().AddJsonOptions(options =>
      {
         options.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;
      });
      

      任何帮助将不胜感激.提前致谢.

      Any help would be appreciated. Thanks in advance.

      推荐答案

      假设您使用最新最好的 ASP .NET Core 3.1 和 System.Text.Json,来处理引用循环需要切换返回"到 Newtonsoft.Json (尽管值得一提的是 System.Text.Json 应该更快.还支持引用循环处理是 即将到来,作为 @Eric J. 在评论中写道):

      Assuming you are using the latest and greatest ASP .NET Core 3.1 with System.Text.Json, to handle reference loops you will need to switch "back" to Newtonsoft.Json (though it worth mentioning that System.Text.Json should be faster. Also support for reference loops handling is coming, as @Eric J. wrote in comments):

      services.AddControllers()
          .AddNewtonsoftJson(x => x.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore)
      

      至于 EF 创建参考循环 - 它被称为 relationship fixup,您对此无能为力(请参阅 这个 答案).AsNoTracking 可以提供一点帮助(但不适用于 Include).我个人的方法是从端点返回 DTO,而不是直接返回实体.

      As for EF creating reference loops - it is called relationship fixup and you can't do a lot about it (see this answer). AsNoTracking can help a little bit (but not in case of Include). My personal approach is to return DTO's from endpoints and not entites directly.

      UPD

      在 .NET 5.0 ReferenceHandler 被引入,所以接下来应该做的伎俩:

      In .NET 5.0 ReferenceHandler is introduced, so next should do the trick:

      services.AddControllersWithViews()
          .AddJsonOptions(options =>
              options.JsonSerializerOptions.ReferenceHandler = ReferenceHandler.Preserve)
      

      这篇关于避免或控制 Entity Framework Core 中的循环引用的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆