我在实体框架中有以下模型:
public class Customer
{
[XmlIgnore]
public virtual ICollection<Customer> Children { get; set; }
public string Name { get; set; }
}
现在我尝试使用web api序列化它:
public class CustomerController:ApiController {
public HttpResponseMessage GetAll()
{
using (var tc = new DataContext())
{
List<Customer> allCustomers = tc.Customers.ToList();
return Request.CreateResponse(HttpStatusCode.OK, allCustomers);
}
}
}
当我这样做并使用POST调用该方法时 我收到以下错误:
&#39; ObjectContent`1&#39;类型无法序列化响应正文 内容类型&#39; application / json;字符集= UTF-8
InnerException:&#34;错误 从儿童中获取价值&#39;上 &#39; System.Data.Entity.DynamicProxies.Customer&#34;
InnerException(2):&#34; The ObjectContext实例已被释放,不能再使用 需要连接的操作。&#34;
customers.Children目前是一个空列表。
我猜这个问题的出现是因为儿童与客户的类型相同,导致了一个&#34;无限序列化循环&#34;。 (我没有更好的词来描述)
我已经尝试过XmlIgnore来阻止该属性被序列化但没有效果。
答案 0 :(得分:4)
不要将导航属性声明为virtual
或禁用延迟加载行为。默认情况下启用延迟加载,通过创建派生代理类型的实例,然后覆盖virtual
属性以添加加载挂钩来实现。因此,如果您想使用XML序列化程序,我建议您关闭延迟加载:
public class YourContext : DbContext
{
public YourContext()
{
this.Configuration.LazyLoadingEnabled = false;
}
}
如果您要加载相关实体(Children
),可以使用Include
扩展方法作为查询的一部分。此行为称为预先加载。
using System.Data.Entity; // For extension method `Include`
List<Customer> allCustomers = tc.Customers.Include(c=>c.Children).ToList();
这些链接可以帮助您更好地理解我在答案中解释的内容:
如果从导航属性中删除virtual
关键字,则POCO实体不符合第二个链接中描述的要求,因此,EF不会创建代理类来延迟加载导航属性。但是,如果您禁用了延迟加载,即使您的导航属性为virtual
,也不会在任何实体中加载它们。使用序列化程序时禁用延迟加载是个好主意。大多数序列化程序通过访问类型实例上的每个属性来工作。
答案 1 :(得分:1)
仅为了知识: 以下也有效:
public class Customer
{
[XmlIgnore,JSonIgnore]
public virtual ICollection<Customer> Children { get; set; }
public string Name { get; set; }
}
神奇的是那里的“JsonIgnore”。
尽管如此:@octavioccl的答案是一个更好的解决方案,需要更多的工作,但创造更好的代码。