如何将实体框架对象序列化为JavaScript Object(JSON)?我尝试使用JSON.NET,但在尝试序列化时遇到以下异常。
异常:Newtonsoft.Json.JsonSerializationException,Message =“Self referencing loop”
答案 0 :(得分:7)
在循环引用方面,听起来您遇到与原始DataContract序列化程序相同的一般问题。虽然相互引用的对象与内存中的对象图相当常见,但如果序列化程序没有特别考虑它,则这种循环引用在序列化时不可避免地会导致无限递归。在常见的非二进制序列化格式(XML和JSON是最常见的两种格式)中,很少有(如果有的话)建立标准来处理循环引用。
Microsoft通过在xml中使用ref语义解决了.NET 3.5 SP1中DataContract序列化程序的循环问题。据我所知,JSON没有这样的东西,这可能就是JSON.NET阻止你序列化对象图形的原因。
我会确保你的对象图中只有可以单向导航的引用,而不是两种方式(即只从父对子,而不是从子到父。)那些父/子和子/父是最常见的循环引用类型。也可能是较低级别的子级最终引用图形的根,导致创建间接循环图(但这些图形往往远不如父/子循环那么常见。)
在对象图中消除任何循环引用后,您应该能够序列化。
答案 1 :(得分:4)
我遇到了这个问题并通过将Newtonsoft.Json.JsonIgnoreAttribute添加到导致循环的属性来解决了这个问题。显然,该属性不会被序列化。为了解决这个问题,我通常会在我的实体中同时拥有外部引用ID和外部类。我意识到这不是直观的(或超级优秀的OO),但它是Julia Lerman在她的“编程实体框架:代码优先”一书中推荐的方式。我发现它有助于消除Entity Framework的几个问题。
public class SomeEntity
{
[JsonIgnore]
public ForeignEntity SomeForeignEntity {get;set;}
public Guid ForeignEntityId {get;set;}
}
更新:我忘了提及我还需要在DbContext上禁用代理,如下所示:
dataContext.Configuration.ProxyCreationEnabled = false;
如果您正在编写服务的代码(如果您正在序列化,这似乎很可能),那么这可能不是问题,但是在禁用代理创建时会丢失一些内容。有关更多详细信息,请参见此处:http://www.sellsbrothers.com/posts/Details/12665。
我正在使用MS Web Api,因此我只是在构建控制器时禁用代理创建:
public class MailingApiController : ApiController
{
public MailingApiController()
{
PreventDeepSerialization();
}
private static void PreventDeepSerialization()
{
var dataContext = Injector.Get<IIntertwyneDbContext>();
dataContext.Configuration.ProxyCreationEnabled = false;
}
....
答案 2 :(得分:1)
为了解决这个问题,我将我的实体转换为基于POCO的Code First。要执行此操作,请在edmx窗口中右键单击并选择:
添加代码生成项&gt;代码标签&gt; EF POCO实体生成器。
请注意,如果您没有看到它,可能需要使用nuget进行安装。
在运行时,EF会将代理类添加到这些对象以进行跟踪,但它们往往会搞乱序列化过程。为了防止这种情况,我们可以简单地将ProxyCreationEnabled设置为false,如下所示:
var context = new YourEntities();
context.Configuration.ProxyCreationEnabled = false;
var results = context.YourEntity.Take(100).ToList();
然后,您可以通过省略默认引用循环来安全地返回JSON.NET序列化数据,如下所示:
return JsonConvert.SerializeObject(results, Formatting.Indented,
new jsonSerializerSettings {
ReferenceLoopHandling = ReferenceLoopHandling.Ignore
});