I have the following model inside an entity framework:
我在实体框架中有以下模型:
public class Customer
{
[XmlIgnore]
public virtual ICollection<Customer> Children { get; set; }
public string Name { get; set; }
}
Now I try to serialize this using web api:
现在我尝试使用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);
}
}
}
When I do this and call the method using POST I receive the following error:
当我这样做并使用POST调用该方法时,我收到以下错误:
The 'ObjectContent`1' type failed to serialize the response body for content type 'application/json; charset=utf-8
'ObjectContent`1'类型无法序列化内容类型'application / json的响应主体;字符集= utf-8的
InnerException: "Error getting value from 'Children' on 'System.Data.Entity.DynamicProxies.Customer"
InnerException:“在'System.Data.Entity.DynamicProxies.Customer'上从'Children'获取值时出错”
InnerException(2): "The ObjectContext instance has been disposed and can no longer be used for operations that require a connection."
InnerException(2):“ObjectContext实例已被释放,不能再用于需要连接的操作。”
customers.Children is currently an empty List.
customers.Children目前是一个空列表。
My guess this problem occurs because Children is of the same type as Customer causing an "infinite serialization loop". (I got no better words to describe that)
我猜这个问题的出现是因为儿童与顾客的类型相同,导致“无限序列化循环”。 (我没有更好的词来描述)
I already tried XmlIgnore to prevent that property to be serialized but with no effect.
我已经尝试过XmlIgnore来防止该属性被序列化但没有效果。
2 个解决方案
#1
4
Don't declare that navigation property as virtual
or disable Lazy Loading behavior. Lazy loading is enable by default and is achieved by creating instances of derived proxy types and then overriding virtual
properties to add the loading hook. So, if you want to work with XML serializer I recommend you turn off lazy loading:
不要将导航属性声明为虚拟或禁用延迟加载行为。默认情况下启用延迟加载,通过创建派生代理类型的实例,然后覆盖虚拟属性以添加加载挂钩来实现。因此,如果您想使用XML序列化程序,我建议您关闭延迟加载:
public class YourContext : DbContext
{
public YourContext()
{
this.Configuration.LazyLoadingEnabled = false;
}
}
In case you want to load the related entity (Children
), you can use the Include
extension method as part of a query. This behavior is called Eager Loading.
如果要加载相关实体(子项),可以使用Include扩展方法作为查询的一部分。此行为称为Eager Loading。
using System.Data.Entity; // For extension method `Include`
List<Customer> allCustomers = tc.Customers.Include(c=>c.Children).ToList();
These links can help you to understand better what I explain in my answer:
这些链接可以帮助您更好地理解我在答案中解释的内容:
- Loading Related Entities
- Requirements for Creating POCO Proxies
加载相关实体
创建POCO代理的要求
If you remove the virtual
keyword from your navigation properties, the POCO entity not meet the requirements described in the second link, so, EF won't create a proxy class to lazy load your navigation properties. But if you disabled lazy loading, even when your navigation properties are virtual
, they won't be loaded in any entity. It's good idea disable lazy loading when you are using a serializer. Most serializers work by accessing each property on an instance of a type.
如果从导航属性中删除虚拟关键字,则POCO实体不符合第二个链接中描述的要求,因此,EF不会创建代理类来延迟加载导航属性。但是,如果禁用延迟加载,即使导航属性是虚拟的,也不会在任何实体中加载它们。在使用序列化程序时禁用延迟加载是个好主意。大多数序列化程序通过访问类型实例上的每个属性来工作。
#2
1
Just for the sake of knowledge: The following also works:
仅仅为了知识:以下也有效:
public class Customer
{
[XmlIgnore,JSonIgnore]
public virtual ICollection<Customer> Children { get; set; }
public string Name { get; set; }
}
The magic is "JsonIgnore" there.
神奇的是那里的“JsonIgnore”。
Nonetheless: @octavioccl 's answer is a much better solution which requires more work but creates better code.
尽管如此:@octavioccl的答案是一个更好的解决方案,需要更多的工作,但创建更好的代码。
#1
4
Don't declare that navigation property as virtual
or disable Lazy Loading behavior. Lazy loading is enable by default and is achieved by creating instances of derived proxy types and then overriding virtual
properties to add the loading hook. So, if you want to work with XML serializer I recommend you turn off lazy loading:
不要将导航属性声明为虚拟或禁用延迟加载行为。默认情况下启用延迟加载,通过创建派生代理类型的实例,然后覆盖虚拟属性以添加加载挂钩来实现。因此,如果您想使用XML序列化程序,我建议您关闭延迟加载:
public class YourContext : DbContext
{
public YourContext()
{
this.Configuration.LazyLoadingEnabled = false;
}
}
In case you want to load the related entity (Children
), you can use the Include
extension method as part of a query. This behavior is called Eager Loading.
如果要加载相关实体(子项),可以使用Include扩展方法作为查询的一部分。此行为称为Eager Loading。
using System.Data.Entity; // For extension method `Include`
List<Customer> allCustomers = tc.Customers.Include(c=>c.Children).ToList();
These links can help you to understand better what I explain in my answer:
这些链接可以帮助您更好地理解我在答案中解释的内容:
- Loading Related Entities
- Requirements for Creating POCO Proxies
加载相关实体
创建POCO代理的要求
If you remove the virtual
keyword from your navigation properties, the POCO entity not meet the requirements described in the second link, so, EF won't create a proxy class to lazy load your navigation properties. But if you disabled lazy loading, even when your navigation properties are virtual
, they won't be loaded in any entity. It's good idea disable lazy loading when you are using a serializer. Most serializers work by accessing each property on an instance of a type.
如果从导航属性中删除虚拟关键字,则POCO实体不符合第二个链接中描述的要求,因此,EF不会创建代理类来延迟加载导航属性。但是,如果禁用延迟加载,即使导航属性是虚拟的,也不会在任何实体中加载它们。在使用序列化程序时禁用延迟加载是个好主意。大多数序列化程序通过访问类型实例上的每个属性来工作。
#2
1
Just for the sake of knowledge: The following also works:
仅仅为了知识:以下也有效:
public class Customer
{
[XmlIgnore,JSonIgnore]
public virtual ICollection<Customer> Children { get; set; }
public string Name { get; set; }
}
The magic is "JsonIgnore" there.
神奇的是那里的“JsonIgnore”。
Nonetheless: @octavioccl 's answer is a much better solution which requires more work but creates better code.
尽管如此:@octavioccl的答案是一个更好的解决方案,需要更多的工作,但创建更好的代码。