序列化对象时出现循环引用错误。一对多关联对象
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 文件中找到带有 <#=codeStringGenerator.UsingDirectives(inHeader: false)#>
的行并在它之前添加:
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 实体的另一个原因。 :)
【讨论】:
以上是关于序列化对象时出现循环引用错误。一对多关联对象的主要内容,如果未能解决你的问题,请参考以下文章
EF实体类,设置导航属性,导致序列化时出现"循环引用"错误,及序列化时间格式解决方案