具有一对多关系的实体框架对象的序列化

时间:2012-10-25 21:09:37

标签: c# entity-framework .net-4.5

我正在尝试将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文章(article 1article 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; }
}

2 个答案:

答案 0 :(得分:83)

当您看到如下对象时:

  

System.Data.Entity.DynamicProxies.Tag_FF17EDDE6893000F7672649A39962DB0CA591C699DDB73E8C2A56203ED7C7B6D

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

实体框架已创建此对象,因为它会跟踪对象何时发生更改,因此当您调用.SaveChanges()时,它可以优化要执行的操作。这种情况的缺点是你实际上并没有使用你定义的特定对象,因此Data Contracts和Frameworks(Json.net)不能像原始POCO对象一样使用它们。

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

首先,Try turning off Proxy object creation on your DbContext

DbContext.Configuration.ProxyCreationEnabled = false;

这将完全禁用为特定DbContext的每个查询创建Proxy对象。 (这不会影响ObjectContext中的缓存对象。)

其次,将 EntityFramework 5.0 + AsNoTracking()一起使用 (ProxyCreationEnabled在EF 5.0中仍然可用)

你也应该能够

DbContext.Persons.AsNoTracking().FirstOrDefault();

DbContext.Persons.
  .Include(i => i.Parents)
  .AsNoTracking()
  .FirstOrDefault();

不是全局禁用DbContext的代理创建,而是仅针对每个查询将其关闭。 (此 DOES 会影响ObjectContext中的缓存对象,它不会被缓存)

答案 1 :(得分:2)

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