C# 具有一对多关系的实体框架对象序列化
我正在尝试将EF与代码和Web API一起使用。在我开始序列化多对多关系之前,我没有任何问题。当我尝试执行以下web api方法时,我收到以下错误消息:C# 具有一对多关系的实体框架对象序列化,c#,entity-framework,.net-4.5,C#,Entity Framework,.net 4.5,我正在尝试将EF与代码和Web API一起使用。在我开始序列化多对多关系之前,我没有任何问题。当我尝试执行以下web api方法时,我收到以下错误消息: public class TagsController : ApiController { private BlogDataContext db = new BlogDataContext(); // GET api/Tags public IEnumerable<Tag> Get
public class TagsController : ApiController
{
private BlogDataContext db = new BlogDataContext();
// GET api/Tags
public IEnumerable<Tag> GetTags()
{
return db.Tags.AsEnumerable();
}
}
公共类标记控制器:ApiController
{
私有BlogDataContext db=新BlogDataContext();
//获取api/标签
公共IEnumerable GetTags()
{
返回db.Tags.AsEnumerable();
}
}
我得到以下错误:
“System.Data.Entity.DynamicProxies.Tag_FF17EDDE689300F767649A39962DB0CA591C699DDB73E8C2A56203ED7C7B6D”
使用数据合同名称
“标签号为EDDE6893000F767264949692DB0CA591C699DDB73E8C2A56203ED7C7B6D:”
这是预料不到的。考虑使用DATACONTracTracever或添加任何
已知类型列表中静态未知的类型-例如,
通过使用KnownTypeAttribute属性或将其添加到
传递给DataContractSerializer的已知类型列表
我已经阅读了一些文章(,),修复方法是添加以下属性:
[DataContract(IsReference=true)]
但这没有任何效果。使用[IgnoreDataMember]也没有效果。唯一可行的选项是将Configuration.ProxyCreationEnabled设置为false。这是我唯一的选择吗?我错过什么了吗
示例POCO对象:
标记
[DataContract(IsReference = true)]
public class Tag
{
public Tag()
{
this.Blogs = new HashSet<Blog>();
}
[Key]
[DataMember]
public int Id { get; set; }
[DataMember]
public string Name { get; set; }
[IgnoreDataMember]
public virtual ICollection<Blog> Blogs { get; set; }
}
[DataContract(IsReference = true)]
public class Blog
{
public Blog()
{
this.Tags = new HashSet<Tag>();
}
[Key]
[DataMember]
public int Id { get; set; }
[DataMember]
public string Name { get; set; }
[IgnoreDataMember]
public virtual ICollection<Tag> Tags { get; set; }
}
[DataContract(IsReference=true)]
公共类标签
{
公共标签()
{
this.Blogs=new HashSet();
}
[关键]
[数据成员]
公共int Id{get;set;}
[数据成员]
公共字符串名称{get;set;}
[IgnoreDataMember]
公共虚拟ICollection博客{get;set;}
}
博客
[DataContract(IsReference = true)]
public class Tag
{
public Tag()
{
this.Blogs = new HashSet<Blog>();
}
[Key]
[DataMember]
public int Id { get; set; }
[DataMember]
public string Name { get; set; }
[IgnoreDataMember]
public virtual ICollection<Blog> Blogs { get; set; }
}
[DataContract(IsReference = true)]
public class Blog
{
public Blog()
{
this.Tags = new HashSet<Tag>();
}
[Key]
[DataMember]
public int Id { get; set; }
[DataMember]
public string Name { get; set; }
[IgnoreDataMember]
public virtual ICollection<Tag> Tags { get; set; }
}
[DataContract(IsReference=true)]
公共类博客
{
公共博客()
{
this.Tags=newhashset();
}
[关键]
[数据成员]
公共int Id{get;set;}
[数据成员]
公共字符串名称{get;set;}
[IgnoreDataMember]
公共虚拟ICollection标记{get;set;}
}
当您看到以下对象时:
System.Data.Entity.DynamicProxies.Tag_FF17EDD689300F7672649A39962DB0CA591C699DDB73E8C2A56203ED7C7B6D
它是运行时EF生成的代理版本,通常被视为POCO对象
Entity Framework创建此对象是因为它跟踪对象的更改时间,因此当您调用.SaveChanges()
时,它可以优化操作。这样做的缺点是您实际上没有使用您定义的特定对象,因此数据契约和框架(Json.net)不能像使用原始POCO对象那样使用它们
要防止EF返回此对象,您有两种选择(ATM):
首先
这将完全禁用为特定DbContext的每个查询创建代理对象。(这不会影响ObjectContext中的缓存对象)
其次,使用EntityFramework 5.0+和
(ProxyCreationEnabled在EF 5.0中仍然可用)
你也应该能够
DbContext.Persons.AsNoTracking().FirstOrDefault();
或
这并不是全局禁用DbContext的代理创建,而是只在每个查询中关闭它。(这确实会影响ObjectContext中的缓存对象,它不会被缓存)我想保留代理创建界面,并发现使用
ProxyDataContractResolver
似乎可以解决这个问题。有关如何在wcf中使用它的参考信息,wcf不完全是WebAPI,但应该会让您走上正确的道路。我遇到了完全相同的问题,我发现唯一的解决方案就是您和Erik Philips所说的。关闭代理创建。IgnoreDataMember
无效的原因是,问题在于代理生成,而不是标记的ICollection
的序列化。我也有同样的问题,您是如何解决的?当我禁用代理创建时,我无法获取父级的值,我需要它。请帮助我。问题是,为了让实体框架跟踪更改,当您向它请求一个实例时,它提供了一个包装好的实例,该实例具有用于更改跟踪的触发器。包装的实例几乎总是无法序列化。@ErikPhilips很抱歉,我无法理解解决方案,所以我不应该禁用代理创建?还是我应该?然后我应该使用dbcontext.class.AsNoTracking().FirstOrDefault()?它到底是做什么的?@Dark_Knight更新了我的答案,我希望它有你想要的细节。非常感谢!我也不得不在EF6上使用这个-你帮我省去了很多挫折@ErikPhilips如果我全局禁用ProxyCreation会有什么后果?您介意向我解释如何使用ProxyDataContractResolver来序列化poco实体吗?我找到的唯一一个例子涉及WCF,但我不知道它是如何工作的。