序列化对象时出现循环引用错误。一对多关联对象

Posted

技术标签:

【中文标题】序列化对象时出现循环引用错误。一对多关联对象【英文标题】:Circular Reference error when serializing objects. One to many associated objects 【发布时间】:2016-10-02 18:20:00 【问题描述】:

我有两个从 EF 自动生成的简单列表:

public partial class Visitor

    public Visitor()
    
        this.Visits = new HashSet<Visit>();
    

    public int Id  get; set; 
    public int PermitId  get; set; 
    public string FirstName  get; set; 
    public string LastName  get; set; 
    public string MiddleName  get; set; 
    public bool IsValid  get; set; 
    public System.DateTime RegistrationDate  get; set; 
    public byte[] Picture  get; set; 
    public virtual ICollection<Visit> Visits  get; set; 


public partial class Visit

    public int Id  get; set; 
    public int VisitType  get; set; 
    public System.DateTime VisitDate  get; set; 
    public Nullable<int> Visitor_Id  get; set; 

    public virtual Visitor Visitor  get; set; 

在 WCF 方法中,我尝试返回以下结果:

[Serializable]
[DataContract(IsReference = true)]
[KnownType(typeof(Visitor))]
[KnownType(typeof(Visit))]
[KnownType(typeof(ICollection<Visit>))]
public class ServiceVisit : IServiceVisit


    public List<Visitor> AllVisitors()
    
        using (var te = new TurnstileDbEntities())
        
            te.Configuration.ProxyCreationEnabled = false;

            return te.Visitors.Include("Visits").ToList();
        
    

但我收到了异常:

尝试序列化参数时出错 http://tempuri.org/:AllVisitorsResult。消息内部异常“对象 类型图 “System.Collections.Generic.HashSet`1[[TurnstileWcfService.Visit, TurnstileWcfService,版本=1.0.0.0,文化=中性, PublicKeyToken=null]]" 包含循环并且不能被序列化,如果 参考跟踪已禁用”。

建议在所有类似的胎面中这样做:

[DataContract(IsReference = true)]

或使用第三方序列化库 (Newtonsoft.Json)。但这不是我的选择。因为我不想在 WinForms 应用程序中使用 Json。 我该如何解决这个问题以及有哪些其他解决方案?

【问题讨论】:

尝试在Visitor 属性上添加[IgnoreDataMember] Visits [NonSerialized()] 如msdn.microsoft.com/en-us/library/…所示 谢谢。 [IgnoreDataMember] 是工作。但就我而言,我使用自动生成的模型。我看到以下评论“如果重新生成代码,将覆盖对此文件的手动更改。”和“手动更改此文件可能会导致您的应用程序出现意外行为。”。我应该在类似的类中包装自动生成的类吗? 如果您与第三方实体打交道,最好不要直接使用它们,而是在您的业务层创建服务于您目的的对象 谢谢。你能给我一个简单的例子来说明如何做得更好。我所做的只是在我的 WCF 服务引用中添加了 ADO.NET 实体数据模型。我没有 BL,这是一个简单的例子,我试图了解 wcf 中的序列化是如何工作的。我是 wcf 的新手。 【参考方案1】:

一个老问题,但我已经多次遇到这个问题,可以通过以下解决方案解决:

[IgnoreDataMember] 从字面上忽略了该成员,.Include 突然变得没有意义。

应该为每个类而不是服务添加 [Serializable][DataContact...][KnownType(typeo...)] 属性:

XAML:

[Serializable]
[DataContract(IsReference = true)]
[KnownType(typeof(Visit))]
public partial class Visit

  public int Id  get; set; 
  public int VisitType  get; set; 
  public System.DateTime VisitDate  get; set; 
  public Nullable<int> Visitor_Id  get; set; 

  public virtual Visitor Visitor  get; set; 

但是由于您的类是自动生成的,因此您必须将这些修改添加到模板文件中。

取决于您所称的模型,将有一个.tt 文件。在我的情况下PolModel.tt

在 .tt 文件中找到带有 &lt;#=codeStringGenerator.UsingDirectives(inHeader: false)#&gt; 的行并在它之前添加:

using System.Runtime.Serialization;

然后:

[Serializable]
[DataContract(IsReference = true)]
[KnownType(typeof(<#=code.Escape(entity)#>))]

在您进行此修改时,您还应该考虑将[DataMember] 属性添加到您的properties,否则它们将不可用。

[Serializable]
[DataContract(IsReference = true)]
[KnownType(typeof(Visit))]
public partial class Visit

  [DataMember]
  public int Id  get; set; 
  [DataMember]
  public int VisitType  get; set; 
  [DataMember]
  public System.DateTime VisitDate  get; set; 
  [DataMember]
  public Nullable<int> Visitor_Id  get; set; 

  [DataMember]
  public virtual Visitor Visitor  get; set; 

【讨论】:

【参考方案2】:

这是由于使用 Include 时 EF 的工作方式。父级有对子级的引用,子级有对父级的引用。 WCF 将永远被困在这两者之间。如果您希望它正确序列化,只需将子项上的所有父引用设置为 null 即可。然后循环引用就消失了。否则,您需要建立自己的模型并从 EF 模型中选择您真正想要的东西,这样您就知道您不会返回无限循环。不直接公开 EF 实体的另一个原因。 :)

【讨论】:

以上是关于序列化对象时出现循环引用错误。一对多关联对象的主要内容,如果未能解决你的问题,请参考以下文章

防止对象图序列化的循环引用

JPA一对多循环引用的解决

EF实体类,设置导航属性,导致序列化时出现"循环引用"错误,及序列化时间格式解决方案

WCF+Nhibernate循环引用导致序列化的问题

EntityFramework中Json序列化的循环引用问题解决--Newtonsoft.Json

序列化类型为XX的对象时检测到循环引用