问题描述
我有一个 Reason 对象:
I have a Reason object:
public class Reason
{
public virtual long Id { get; set; }
public virtual string Name { get; set; }
public virtual Company Company {get;set;}
}
我正在使用实体框架 4,公司是公司的导航属性.
我还使用网络服务将数据返回给客户端.
我有返回原因的网络方法:
I am using entity framework 4 and Company is navigation property to Company.
I also use webservices in order to return data to the client.
I have web method that returns Reasons:
[WebMethod]
public Reason[] GetCallReasons()
{
IReasonRepository rep =
ObjectFactory.GetInstance<IReasonRepository>();
return rep.GetReasonsList().ToArray();
}
由于 ef4,我在执行 web 方法时遇到以下异常:
Because of the ef4 I get the following exception for executing the web method:
A circular reference was detected while serializing an object of type 'System.Data.Entity.DynamicProxies.Reason_24A0E4BBE02EE6BC2CF30BB56CFCB670C7D9D96D03D40AF4D174B89C9D3C5537'
问题出现是因为ef4添加了无法序列化的属性:
The problem accurs because ef4 adds property that can't be serialized:
为了解决这个问题并消除错误,我可以通过不使其成为虚拟或删除导航属性来禁用导航属性.但是我需要它并想使用延迟加载功能.
In order to solve this and eliminate the error, I can disable the navigation property by not making it virtual or by remove the navigation property. But I neet it and want to use the lazy loading feature.
我也可以为 Reason 编写特定的序列化程序,但我有很多类在我的 Web 服务中使用,并且为所有这些类编写序列化程序需要大量的工作.
I also can write spesific serializer for Reason but I have many many classes the I used in my web-services and write a serializer for all of them is a lot of work.
我该如何解决这个异常?..
How can I solve this exception?..
推荐答案
有多种解决方案可以解决您的问题,它们实际上取决于您使用的服务类型和序列化类型:
There are multiple solutions for your problem and they really depend on the type of service you are using and on the type of serialization:
- 正如@Mikael 已经建议的那样,干净的方法是使用 DTO(数据传输对象).DTO 是一种特殊的对象,它可以准确地传输您需要的东西,仅此而已.您可以简单地创建不包含循环引用的 DTO,并使用 AutoMapper 在实体和 DTO 之间进行映射,反之亦然.为@Mikael +1,因为他是第一个提到这一点的人.
- The clean approach is using DTO (data transfer objects) as @Mikael already suggested. DTO is special object which transfers exactly what you need and nothing more. You can simply create DTOs to not contain circular references and use AutoMapper to map between entities and DTOs and vice versa. +1 for @Mikael because he was the first to mentioned this.
所有其他方法都基于@Haz 建议的 tweeking 序列化:
All other approaches are based on tweeking serialization as @Haz suggested:
- WCF 和
DataContractSerializer
:使用DataContract[IsReference=true]
显式标记您的实体,并使用[DataMember]
属性标记所有属性.这将允许您使用循环引用.如果您使用 T4 模板生成实体,则必须对其进行修改才能为您添加这些属性. - WCF 和
DataContractSerializer
:隐式序列化.使用[IgnoreDataMember]
属性标记相关导航属性之一,以便属性不被序列化. XmlSerializer
:用[XmlIgnore]
属性标记一个相关的导航属性- 其他序列化:使用
[NonSerialized]
标记一个相关的导航属性(+1 表示他是第一个提到这一点的 Haz)用于常见序列化或[ScriptIgnore]
用于一些与 JSON 相关的序列化.
- WCF and
DataContractSerializer
: explicitly mark your entities withDataContract[IsReference=true]
and all properties with[DataMember]
attributes. This will allow you to use circular references. If you are using T4 template to generate entities you must modify it to add these attributes for you. - WCF and
DataContractSerializer
: implicit serialization. Mark one of related navigation properties with[IgnoreDataMember]
attribute so that property is not serialized. XmlSerializer
: mark one fo related navigation properties with[XmlIgnore]
attribute- Other serializations: mark one of related navigation properties with
[NonSerialized]
(+1 for Haz he was the first to mention this) for common serialization or[ScriptIgnore]
for some JSON related serialization.
这篇关于ef4 导致 Web 服务中的循环引用的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!