我试图将EF与Code First和Web API结合使用。在开始序列化多对多关系之前,我没有任何问题。当我尝试执行下面的以下Web api方法时,出现以下错误消息:
public class TagsController : ApiController { private BlogDataContext db = new BlogDataContext(); // GET api/Tags public IEnumerable<Tag> GetTags() { return db.Tags.AsEnumerable(); } }
我收到以下错误:
:“System.Data.Entity.DynamicProxies.Tag_FF17EDDE6893000F7672649A39962DB0CA591C699DDB73E8C2A56203ED7C7B6D”数据合同名称“Tag_FF17EDDE6893000F7672649A39962DB0CA591C699DDB73E8C2A56203ED7C7B6D http://schemas.datacontract.org/2004/07/System.Data.Entity.DynamicProxies预计不会”。考虑使用DataContractResolver或将任何静态未知的类型添加到已知类型的列表中- 例如,通过使用KnownTypeAttribute属性或将它们添加到传递给DataContractSerializer的已知类型的列表中。
我读过一些SO文章(第1条,第2条),解决方法是添加以下属性:
[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; } }
当您看到类似的对象时:
System.Data.Entity.DynamicProxies.Tag_FF17EDDE6893000F7672649A39962DB0CA591C699DDB73E8C2A56203ED7C7B6D
它是运行时由EF生成的 代理 版本,通常称为POCO对象。
实体框架之所以创建此对象,是因为它跟踪对象的更改时间,因此在调用.SaveChanges()它时可以优化操作。这样做的缺点是您实际上并未使用定义的特定对象,因此数据合约和框架(Json.net)无法像使用原始POCO对象那样使用它们。
.SaveChanges()
要防止EF返回此对象,您有两种选择(ATM):
首先,尝试在DbContext上关闭Proxy对象的创建。
DbContext.Configuration.ProxyCreationEnabled = false;
这将完全禁用对特定DbContext的每个查询的代理对象的创建。(这不会影响ObjectContext中的 缓存 对象)。
其次,将 EntityFramework 5.0+ 与AsNoTracking()一起使用 (ProxyCreationEnabled在EF 5.0中仍然可用)
您还应该能够
DbContext.Persons.AsNoTracking().FirstOrDefault();
要么
DbContext.Persons. .Include(i => i.Parents) .AsNoTracking() .FirstOrDefault();
不会 全局 禁用DbContext的代理创建,而是仅在每次查询时将其关闭。(这 确实 会影响ObjectContext中的 缓存 对象,但不会缓存)