繁体   English   中英

如何解决 System.Text.Json.JsonException:在实体框架中检测到可能的 object 循环?

[英]How to resolve System.Text.Json.JsonException: A possible object cycle was detected in Entity Framework?

我有一个带有表/数据的数据库,所以我使用了 db first 方法,使用以下命令来搭建模型:

dotnet ef dbcontext scaffold "Server=.;Database=MyDb;Trusted_Connection=True;" Microsoft.EntityFrameworkCore.SqlServer -o Models

这已经生成了与我的表相对应的DbContext和几个 model 类。 此问题仅涉及 2 个模型,因此我提供以下代码:

个人.cs:

using System;
using System.Collections.Generic;

namespace MyApp.Models
{
    public partial class Person
    {
        public Person()
        {
            Profiles= new HashSet<Profile>();
        }

        public int Id { get; set; }
        public string Email { get; set; } = null!;
        public string Password { get; set; } = null!;

        public virtual ICollection<Profile> Profiles { get; set; }
    }
}

个人资料.cs:

using System;
using System.Collections.Generic;

namespace MyApp.Models
{
    public partial class Profile
    {
        public Profile()
        {
            Sales = new HashSet<Sale>();
        }

        public int Id { get; set; }
        public int PersonId { get; set; }
        public string ProfileName { get; set; } = null!;

        public virtual Person Person { get; set; } = null!;
        public virtual ICollection<Sale> Sales { get; set; }
    }
}

在 controller 我正在尝试以下查询:

var person = await _context.Person
                           .AsNoTracking()
                           .Where(c => c.Email == 'test@testmail.com')
                           .ToListAsync();

这行得通。 但是以下查询会引发错误:

var profiles = await _context.Person
                             .AsNoTracking()
                             .Where(c => c.Email == 'test@testmail.com')
                             .Include(c => c.Profiles)
                             .ToListAsync();

错误:

System.Text.Json.JsonException:检测到可能的 object 循环。 这可能是由于循环或 object 深度大于最大允许深度 32。考虑在 JsonSerializerOptions 上使用 ReferenceHandler.Preserve 以支持循环。

小路:
$.Profiles.Person.Profiles.Person.Profiles.PersonProfiles.PersonProfiles.PersonProfiles.PersonProfiles.PersonProfiles.PersonProfiles.Person.Id。

在 System.Text.Json.ThrowHelper.ThrowJsonException_SerializerCycleDetected(Int32 maxDepth)
at System.Text.Json.Serialization.JsonConverter 1.TryWrite(Utf8JsonWriter writer, T& value, JsonSerializerOptions options, WriteStack& state) at System.Text.Json.Serialization.Metadata.JsonPropertyInfo 1.GetMemberAndWriteJson(Object obj, WriteStack& state, Utf8JsonWriter writer )

你得到这个的原因是你正在序列化一个有循环的 object 图,这是一个典型的 EF DB 实体图

想象一下,您有一个拥有一个 Profile 的 Person,并且该 Profile 有一个 Person(返回父 Person 的链接)

可以编写 C# 代码,如:

myPerson.Profiles.First().Person.Profiles.First().Person.Profiles.First().Person.Profiles.First().Person.Profiles.First().Person..

你可以永远这样 go ..

..这就是 json 序列化程序在尝试序列化每个配置文件的每个属性时也在做的事情

你有几个选择..

  • 您可以在序列化之前修改图表:将每个 Profile 的 Person(或任何级别 N 属性是第一个链接回早期 Nx 的属性)设置为 null 以停止循环

  • 您可以序列化没有循环的 object 图,例如在序列化之前将您的 EF 实体 map 到的一组 DTO

  • 您可以告诉 Newtonsoft 观看引用而不设置它之前看到的任何内容:

string json = JsonConvert.SerializeObject(joe, Formatting.Indented, new JsonSerializerSettings
{
    ReferenceLoopHandling = ReferenceLoopHandling.Ignore
});

我说,大多数人会避免看到这种情况,因为他们选择了选项 2; 通常我们不会序列化我们的数据库实体,我们有一组专门为我们的前端设计的类,它们可能看起来不同等; 很少有系统的前端完全且准确地需要看起来与数据库建模完全相同的数据对象。 如果那些以前端为中心的对象没有周期(一个人可能有一个配置文件列表,但没有必要将配置文件链接回来,因为在绘制 hi 时它使用得太低了)它们不会导致这个问题。

小心选项1; 如果在将图形修改为对序列化程序友好之后调用上下文中的保存(出于任何原因),您最终可能会断开数据库中的关系。 3有点杂乱无章,可以解决由于没有完成2而导致的问题,但2是go的更多努力

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM