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

时间:2016-06-02 20:32:08

标签: c# entity-framework wcf serialization

我有两个从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。消息InnerException“对象   类型图   “System.Collections.Generic.HashSet`1 [[TurnstileWcfService.Visit,   TurnstileWcfService,Version = 1.0.0.0,Culture = neutral,   PublicKeyToken = null]]“包含循环,如果是,则无法序列化   参考跟踪已禁用“。

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

[DataContract(IsReference = true)]

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

2 个答案:

答案 0 :(得分:0)

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

[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; }
}

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

取决于您所谓的模型,会有一个.tt文件。就我而言PolModel.tt

在.tt文件中找到<#=codeStringGenerator.UsingDirectives(inHeader: false)#>行,然后添加:

using System.Runtime.Serialization;

之后:

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

enter image description here

当您参与其中并进行此修改时,您还应考虑将[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; }
}

答案 1 :(得分:0)

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