2012-10-25 65 views
32

我試圖使用與EF代碼第一次和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' with data contract name 'Tag_FF17EDDE6893000F7672649A39962DB0CA591C699DDB73E8C2A56203ED7C7B6D: http://schemas.datacontract.org/2004/07/System.Data.Entity.DynamicProxies ' is not expected. Consider using a DataContractResolver or add any types not known statically to the list of known types - for example, by using the KnownTypeAttribute attribute or by adding them to the list of known types passed to 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; } 
} 
+1

我有完全相同的問題,我發現的唯一的解決辦法是爲你,埃裏克飛利浦曾表示。關閉代理創建。究其原因'IgnoreDataMember'沒有效果是因爲問題出在代理生成,不Tags'的'了'ICollection'的系列化。 –

+0

我有同樣的問題,你是如何解決它的? 當我禁用代理的創建,然後我不能得到家長的價值觀,這是我需要它。 PLZ幫助我。 –

回答

79

當你看到一個物體,如:

System.Data.Entity.DynamicProxies.Tag_FF17EDDE6893000F7672649A39962DB0CA591C699DDB73E8C2A56203ED7C7B6D

這是一個代理的運行EF生成的版本是什麼通常會被認爲是POCO對象。

實體框架,因爲它跟蹤時的對象發生了變化,所以當你調用.SaveChanges()它可以優化做什麼創造了這個對象。這樣做的缺陷是你沒有實際使用您定義的特定對象,因此數據合同和框架(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的,它是不緩存)

+4

我以爲代碼首先是專爲POCO ... –

+1

的問題是,爲了使實體框架來追蹤變化,當你問一個實例,它提供了對更改跟蹤觸發器被包裹的情況。包裝的實例幾乎總是不能被序列化。 –

+0

你的我的英雄! – Hugo

2

我想離開的代理創建inteact,發現使用ProxyDataContractResolver似乎解決這個問題對我來說。見msdn關於如何在WCF中,這是不完全的WebAPI使用它的引用,但應該讓你沿着正確的道路去。

+1

你介意向我解釋如何使用ProxyDataContractResolver到sereialize POCO實體?我設法找到的唯一例子涉及WCF,我無法弄清楚它是如何工作的。 –

0
db.Configuration.ProxyCreationEnabled = false; 

將解決您的問題