34

我正在尝试将 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; }
}
4

2 回答 2

89

当你看到这样的对象时:

System.Data.Entity.DynamicProxies.Tag_FF17EDDE6893000F7672649A39962DB0CA591C699DDB73E8C2A56203ED7C7B6D

它是通常被视为 POCO 对象的代理的运行时 EF 生成版本。

Entity Framework 已创建此对象,因为它会跟踪对象何时更改,因此当您调用.SaveChanges()它时可以优化要执行的操作。这样做的缺点是您实际上并没有使用您定义的特定对象,因此数据合同和框架(Json.net)不能像使用原始 POCO 对象那样使用它们。

要防止 EF 返回此对象,您有两种选择(ATM):

首先,尝试关闭 DbContext 上的代理对象创建

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 中的缓存对象,它不会被缓存)

于 2012-10-25T21:34:57.433 回答
3

我想让代理创建保持不变,并发现使用ProxyDataContractResolver似乎可以解决我的问题。有关如何在 wcf 中使用它的参考,请参阅msdn,这不完全是 WebAPI,但应该让您走上正确的道路。

于 2014-09-16T13:50:40.297 回答