在 Json.net 中序列化一对多关系

Posted

技术标签:

【中文标题】在 Json.net 中序列化一对多关系【英文标题】:Serialize one to many relationships in Json.net 【发布时间】:2011-08-11 18:28:48 【问题描述】:

我首先使用实体​​框架代码进行数据访问,并且我有一个包含员工集合的公司类。 Employee 类也有一个 Company 属性。

我希望能够对 Company 进行序列化,并将员工列表包含在序列化中。

这是公司:

public class Company

public long Id  get; set; 
public string Name  get; set; 
public DateTime? Established  get; set; 

public virtual IList<Employee> Employees  get; set; 

public DateTime? DateCreated  get; set; 
public DateTime? DateUpdated  get; set; 

这里是员工

public class Employee

public long Id  get; set; 
public string FirstName  get; set; 
public string LastName  get; set; 
public int Age  get; set; 

public virtual Company Company  get; set; 

public DateTime? DateCreated  get; set; 
public DateTime? DateUpdated  get; set; 

当我尝试序列化 Company 对象时,出现序列化异常“检测到类型的自引用循环”。

谢谢。

【问题讨论】:

JSON.NET Error Self referencing loop detected for type的可能重复 我知道这个问题(稍微)旧一些,但这个问题的答案更好。这也是我要发送所有其他副本的地方。 【参考方案1】:

更新答案

您可以:

重新配置 json.net 以忽略 自引用循环 使用 [JsonIgnore] 属性 使用自定义转换器删除 子导航 或者您可以使用数据传输对象

【讨论】:

我试过了,它导致了堆栈溢出,即无限循环......另外,你是如何配置它来忽略自引用的。也许您以其他可行的方式做到了... 那你有设计问题。您需要删除一个引用或使用在员工方面只有一个引用的 POCO。我在我的智能手机上,所以我无法检查它。我认为客户上的员工参考不正确。 您能详细说明“设计问题”是什么意思吗?课程超级简单。 Company 有一个 IList 属性,而 Employee 有一个 Company 属性。 不是最好的,但可能是一种解决方案,即在没有导航的情况下创建数据访问对象。在我的一些项目中,我也在做同样的事情。但这只有在您不需要另一侧的导航时才有效。 我刚刚开始了一个新项目,然后就来了。我正在使用数据传输对象,它现在解决了我的问题。但是你也可以使用[JsonIgnore]。我会用这个更新我的帖子。【参考方案2】:

我认为他们已经在最新版本中修复了这个问题。

查看“序列化和反序列化 JSON -> 序列化和保留对象引用”部分下的 help docs。

在初始化 JSON.Net Serializer 时设置此设置:

PreserveReferencesHandling = PreserveReferencesHandling.Objects;

所以一个例子是这样的:

var serializerSettings = new JsonSerializerSettings  PreserveReferencesHandling = PreserveReferencesHandling.Objects ;

string json = JsonConvert.SerializeObject(people, Formatting.Indented, serializerSettings);

我验证了这适用于我的代码优先解决方案以及导航属性中的循环引用。如果您查看生成的 JSON,它应该到处都有“$id”和“$ref”属性。

【讨论】:

就此主题写了一篇博文:johnnycode.com/blog/2012/04/10/… 为我指明了正确的方向。请注意,JsonFormatter 现在已嵌入 WebApi,因此您需要做的就是设置 PreserveReferencesHandling 设置。 你有没有想过我在发布 json 时需要他们的关系,因为一个学生在健身房有很多预订【参考方案3】:

如果这对任何人都有帮助,我想我会记录下我们在使用 Entity Framework 4.3.1 和 JSON.Net 4.5.3 时如何解决同样的错误。

我们使用的是 Database First DbContext 方法。根据我们的需要,我们可以使用[JsonIgnore] 属性来解决它。诀窍在于,当您从数据库刷新时,自动生成的实体类的更改会被覆盖,使用 Database First,您可以使用this *** post 中给出的“元数据伙伴类”方法添加属性。

以下是代码摘录。我们有一个与“公司”和“用户”对象有关系的“查询”对象 (class Query)。在一个新的类文件中,我们用[MetadataType] 属性声明部分类,然后在我们指定的QueryMetadata 类中,我们注释我们想要忽略的成员——即EF4.x 添加到的public virtual 成员表达关系(又名导航属性)。

Query 实体也有外键字段(在我们的例子中名为 FK_UserFK_Company)。这些字段不需要[JsonIgnore] 属性——它们可以使用它们的外键值进行序列化。

[MetadataType(typeof(QueryMetadata))]
public partial class Query




public class QueryMetadata

    [JsonIgnore]
    public virtual Company company  get; set; 
    [JsonIgnore]
    public virtual User user  get; set; 

但是,如果我们实际上还必须序列化相关的 Company 或 User 对象,我们就碰壁了! John Bubriski here 建议的方法对我们不起作用,因为我们想依赖实体框架更改跟踪。

【讨论】:

【参考方案4】:

如果您在使用 WebApi 时遇到此错误,您可以在 WebApiConfig.cs 中添加以下内容,以便 json.net 忽略循环引用

config.Formatters.JsonFormatter.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore; 

Microsoft : Loop Reference handling in Web API

【讨论】:

由于某种原因我收到了cannot resolve symbol ReferenceLoopHandling【参考方案5】:

如果您使用的是 WebAPI EntityFrameworkCore 2.0,此解决方案不起作用,您需要在 Startup.cs->ConfigureServices 上进行设置:

.AddJsonOptions(options => 
                    var settings = options.SerializerSettings;
                    settings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;
                );

【讨论】:

似乎忽略某些东西是不好的,但我已经在多个地方看到过这种情况。为什么这样做还不错?

以上是关于在 Json.net 中序列化一对多关系的主要内容,如果未能解决你的问题,请参考以下文章

Django.rest_framework:如何序列化一对多?

Json序列化,有多对一和多对多关系时出现的问题

如何使用 RestKit 序列化多态对多核心数据关系?

DRF 一对多序列化与反序列化

0015 DRF框架开发(02 创建模型)

Linq 语法