使用EF和WebApi将父/子对象序列化

我在entity framework中有以下模型:

public class Customer { [XmlIgnore] public virtual ICollection Children { get; set; } public string Name { get; set; } } 

现在我尝试使用web api序列化它:

 public class CustomerController:ApiController { public HttpResponseMessage GetAll() { using (var tc = new DataContext()) { List allCustomers = tc.Customers.ToList(); return Request.CreateResponse(HttpStatusCode.OK, allCustomers); } } } 

当我这样做并使用POST调用该方法时,我收到以下错误:

‘ObjectContent`1’类型无法序列化内容类型’application / json的响应主体; 字符集= utf-8的

InnerException:“在’System.Data.Entity.DynamicProxies.Customer’上从’Children’获取值时出错”

InnerException(2):“ObjectContext实例已被释放,不能再用于需要连接的操作。”

customers.Children目前是一个空列表。

我猜这个问题的出现是因为儿童与顾客的类型相同,导致“无限序列化循环”。 (我没有更好的词来描述)

我已经尝试过XmlIgnore来防止该属性被序列化但没有效果。

不要将导航属性声明为virtual或禁用延迟加载行为。 默认情况下启用延迟加载,通过创建派生代理类型的实例,然后覆盖virtual属性以添加加载挂钩来实现。 因此,如果您想使用XML序列化程序,我建议您关闭延迟加载:

 public class YourContext : DbContext { public YourContext() { this.Configuration.LazyLoadingEnabled = false; } } 

如果要加载相关实体( Children ),可以使用Include扩展方法作为查询的一部分。 此行为称为Eager Loading

 using System.Data.Entity; // For extension method `Include` List allCustomers = tc.Customers.Include(c=>c.Children).ToList(); 

这些链接可以帮助您更好地理解我在答案中解释的内容:

  • 加载相关实体
  • 创建POCO代理的要求

如果从导航属性中删除virtual关键字,则POCO实体不符合第二个链接中描述的要求,因此,EF不会创建代理类来延迟加载导航属性。 但是,如果禁用延迟加载,即使导航属性是virtual ,也不会在任何实体中加载它们。 在使用序列化程序时禁用延迟加载是个好主意。 大多数序列化程序通过访问类型实例上的每个属性来工作。

仅仅为了知识:以下也有效:

 public class Customer { [XmlIgnore,JSonIgnore] public virtual ICollection Children { get; set; } public string Name { get; set; } } 

神奇的是那里的“JsonIgnore”。

尽管如此:@octavioccl的答案是一个更好的解决方案,需要更多的工作,但创建更好的代码。