【问题标题】:Serializing Parent/Child Object to with EF and WebApi使用 EF 和 WebApi 序列化父/子对象
【发布时间】:2015-05-21 13:55:20
【问题描述】:

我在实体框架中有以下模型:

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 调用该方法时 我收到以下错误:

“ObjectContent`1”类型未能序列化响应正文 内容类型'应用程序/json;字符集=utf-8

InnerException:“错误 从“儿童”中获得价值 'System.Data.Entity.DynamicProxies.Customer"

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

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

我猜这个问题的发生是因为 Children 与 Customer 的类型相同,导致“无限序列化循环”。 (我没有更好的词来形容)

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

【问题讨论】:

    标签: c# json entity-framework serialization asp.net-web-api


    【解决方案1】:

    不要将该导航属性声明为 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<Customer> allCustomers = tc.Customers.Include(c=>c.Children).ToList();
    

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

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

    【讨论】:

    • 谢谢。我已经通过使用“JsonIgnore”“解决”了这个问题,但你的回答似乎是处理这个问题的更好方法。
    • Include 方法需要一个字符串...msdn.microsoft.com/query/…
    • 嗨@FlorianWinter,有两个Include 方法,一个需要您指出的字符串,另一个是使用表达式的扩展方法,请参阅第一个引用的链接
    • @octavioccl 谢谢。这并不明显。
    【解决方案2】:

    只是为了知识: 以下也有效:

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

    神奇之处在于“JsonIgnore”。

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

    【讨论】:

    • 但是如何在运行中做呢?
    猜你喜欢
    • 1970-01-01
    • 2014-10-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-05-13
    相关资源
    最近更新 更多