检测到entity framework自我引用循环

我有一个奇怪的错误。 我正在尝试.NET 4.5 Web API,entity framework和MS SQL Server。 我已经创build了数据库并设置了正确的主键和外键。

我创build了一个.edmx模型,并导入了两个表:Employee和Department。 一个部门可以有很多员工,这种关系是存在的。 我使用脚手架选项创build了一个名为EmployeeController的新控制器,以使用Entity Framework创build具有读取/写入操作的API控制器。 在向导中,selectEmployee作为模型,并为数据上下文提供正确的实体。

所创build的方法如下所示:

public IEnumerable<Employee> GetEmployees() { var employees = db.Employees.Include(e => e.Department); return employees.AsEnumerable(); } 

当我通过/ api / Employee调用我的API时,出现以下错误:

“ObjectContent`1”types未能序列化内容types为“application / json; … System.InvalidOperationException“,”StackTrace“:null,”InnerException“:{”Message“:”发生了错误“,”ExceptionMessage“:”检测到types为“System.Data.Entity.DynamicProxies .Employee_5D80AD978BC68A1D8BD675852F94E8B550F4CB150ADB8649E8998B7F95422552' 。 Path'[0] .Department.Employees'。“,”ExceptionType“:”Newtonsoft.Json.JsonSerializationException“,”StackTrace“:”…

为什么它是自引用[0]。部门雇员? 这并没有太多的意义。 我希望这发生,如果我有我的数据库中循环引用,但这是一个非常简单的例子。 有什么可能会出错?

那么基于Json.net的默认Json formater的正确答案是将ReferenceLoopHandling设置为Ignore

只需将其添加到Global.asax中的Application_Start

 HttpConfiguration config = GlobalConfiguration.Configuration; config.Formatters.JsonFormatter .SerializerSettings .ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore; 

这是正确的方法。 它会忽略指向对象的引用。

其他响应集中在更改排除数据或创build门面对象时返回的列表,有时这不是选项。

使用JsonIgnore属性来限制引用可能很耗时,如果你想从另一个点开始序列化树,那将是一个问题。

发生这种情况是因为您试图直接序列化EF对象集合。 由于部门与员工和部门之间有联系,所以JSON序列化程序将循环地读取d.Employee.Departments.Employee.Departments等内容。

要在序列化之前解决这个问题,请用你想要的道具创build一个匿名types

示例(伪代码):

 departments.select(dep => new { dep.Id, Employee = new { dep.Employee.Id, dep.Employee.Name } }); 

我有同样的问题,并发现你可以应用[JsonIgnore]属性的导航属性,你不想被序列化。 它仍然会连续化父代和子代实体,但只是避免了自引用循环。

主要问题是序列化与其他实体模型(外键关系)有关系的实体模型。 这个关系导致自引用这将抛出exception,而序列化为json或xml。 有很多select。 不使用自定义模型序列化实体模型。使用Automapper或Valueinjector映射到自定义模型(对象映射)的实体模型数据的值或数据然后返回请求,并将序列化,而没有任何其他问题。 或者你可以序列化实体模型,所以先在实体模型中禁用代理

 public class LabEntities : DbContext { public LabEntities() { Configuration.ProxyCreationEnabled = false; } 

要保存XML中的对象引用,您有两个选项。 更简单的选项是将[DataContract(IsReference = true)]添加到您的模型类。 IsReference参数启用了oibject引用。 请记住,DataContract使select序列化,因此您还需要将DataMember属性添加到属性:

 [DataContract(IsReference=true)] public partial class Employee { [DataMember] string dfsd{get;set;} [DataMember] string dfsd{get;set;} //exclude the relation without giving datamember tag List<Department> Departments{get;set;} } 

在global.asax中使用Json格式

 var json = GlobalConfiguration.Configuration.Formatters.JsonFormatter; json.SerializerSettings.PreserveReferencesHandling = Newtonsoft.Json.PreserveReferencesHandling.All; 

以xml格式

 var xml = GlobalConfiguration.Configuration.Formatters.XmlFormatter; var dcs = new DataContractSerializer(typeof(Employee), null, int.MaxValue, false, /* preserveObjectReferences: */ true, null); xml.SetSerializer<Employee>(dcs); 

消息错误意味着你有一个自引用循环。

你生产的json就像这个例子(有一个雇员的名单):

 [ employee1 : { name: "name", department : { name: "departmentName", employees : [ employee1 : { name: "name", department : { name: "departmentName", employees : [ employee1 : { name: "name", department : { and again and again.... } ] } } ] } } 

]

你必须告诉数据库上下文,当你请求某些东西时,你不想获得所有链接的实体。 DbContext的选项是Configuration.LazyLoadingEnabled

我发现的最好的方法是创build一个序列化的上下文:

 public class SerializerContext : LabEntities { public SerializerContext() { this.Configuration.LazyLoadingEnabled = false; } } 

我也可以考虑为每个控制器/操作添加明确的样本,这里也包括:

http://blogs.msdn.com/b/yaohuang1/archive/2012/10/13/asp-net-web-api-help-page-part-2-providing-custom-samples-on-the-help- page.aspx

即config.SetActualResponseType(typeof(SomeType),“Values”,“Get”);

添加一行Configuration.ProxyCreationEnabled = false; 在你的上下文模型部分类定义的构造函数中。

  public partial class YourDbContextModelName : DbContext { public YourDbContextModelName() : base("name=YourDbContextConn_StringName") { Configuration.ProxyCreationEnabled = false;//this is line to be added } public virtual DbSet<Employee> Employees{ get; set; } protected override void OnModelCreating(DbModelBuilder modelBuilder) { } } 

我只有一个模型我想用,所以我结束了以下代码:

 var JsonImageModel = Newtonsoft.Json.JsonConvert.SerializeObject(Images, new JsonSerializerSettings { ReferenceLoopHandling = ReferenceLoopHandling.Ignore });