2011-04-23 80 views
4

循环引用我有一个原因对象:EF4导致Web服务

public class Reason 
{ 
    public virtual long Id { get; set; } 
    public virtual string Name { get; set; } 
    public virtual Company Company {get;set;} 
} 

我使用实体框架4和公司是导航属性到公司。
我也使用web服务为了返回数据到客户端。
我有一个返回的原因Web方法:

[WebMethod] 
    public Reason[] GetCallReasons() 
    { 
     IReasonRepository rep = 
      ObjectFactory.GetInstance<IReasonRepository>(); 
     return rep.GetReasonsList().ToArray(); 
    } 

因为EF4我得到下面的异常用于执行Web方法:

A circular reference was detected while serializing an object of type 'System.Data.Entity.DynamicProxies.Reason_24A0E4BBE02EE6BC2CF30BB56CFCB670C7D9D96D03D40AF4D174B89C9D3C5537' 

问题accurs因为EF4增加属性,不能被序列化: Image of the watch panel on rep.GetReasonsList().ToArray()

为了解决这个问题,并消除错误,我可以通过不使其虚拟或通过删除导航本身来禁用导航属性TY。但我neet它,并希望使用延迟加载功能。

我也可以为Reason编写特定的序列化程序,但我有很多很多的类,我在我的web服务中使用并为它​​们编写序列化程序是很多工作。

我怎样才能解决这个例外?..

回答

11

有您的问题多种解决方案,他们真的取决于你所使用的服务类型和序列化的类型:

  • 的清洁方法是使用DTO(数据传输对象)作为@Mikael已经建议。 DTO是一种特殊的对象,它可以正确地传输你所需要的东西,仅此而已您可以简单地创建DTO,使其不包含循环引用,并使用AutoMapper在实体和DTO之间进行映射,反之亦然。 @Mikael +1,因为他是第一个提到这个。

所有其他的方法是基于tweeking的序列化@Haz建议:

  • WCF和DataContractSerializer:明确标示与DataContract[IsReference=true]你的实体和属性[DataMember]所有属性。这将允许您使用循环引用。如果您使用T4模板生成实体,则必须修改它以为您添加这些属性。
  • WCF和DataContractSerializer:隐式序列化。使用[IgnoreDataMember]属性标记相关导航属性之一,以便属性不被序列化。
  • XmlSerializer:标记一个fo与[XmlIgnore]属性
  • 其他序列化相关的导航属性:标记一个相关的导航性能与[NonSerialized](+1哈兹他是第一个提到这一点),共同序列化或[ScriptIgnore]一些JSON相关序列化。
+0

多么痛苦的做法。至少你可以做到。 – 2011-06-28 18:47:43

4

您还没有提供为您的公司类定义....但我猜你有理由为属性的集合。

在SOA环境中延迟加载实际上并不奏效。你不能在一个序列化的类上进行无限制的懒惰导航,一旦你离开webmethod,你就无法从webmethod使用者回调原始数据环境来查找适当的东西...所以序列化程序将尝试访问所有属性,包括序列化时的惰性属性。

您需要禁用循环引用的一部分序列化,无论是在公司类的原因集合还是在原因类公司的公司。

您可以使用“NotSerialized”属性来禁用特定字段的序列化。

8

我通常为web服务编写特定的类。虽然这是一些额外的工作,但它具有的优点是,Web服务变得更加强大,因为实体中的小改动不会消失,并会在消费者/ JavaScript侧面悄然失败。例如,如果我更改属性的名称。

您可以通过一些方法来减少工作量,一种方法是使用可以在对象之间自动映射的AutoMapper。