11

我在這個問題上打破了我的頭。我在網上找到了關於它的東西,但沒有一個明確的答案。我的問題:帶EF代碼優先的WebApi在生成父子關係時產生錯誤

我有類在MVC3 Web應用程序的模型部分: 父類和ChildClass 在父類有類型列表的屬性Children

我使用EF代碼首先,整齊地產生父表和我的數據庫中的子表。

現在我需要一個REST服務,它返回一個List或一個ParentClass。

當我從ParentClass中刪除屬性Children時沒有問題。但是對於這個兒童,我一直在聽到一個錯誤。

錯誤:"The type System.Data.Entity.DynamicProxies.ParentClass_A0EBE0D1022D01EB84B81873D49DEECC60879FC4152BB115215C3EC16FB8003A was not expected. Use the XmlInclude or SoapInclude attribute to specify types that are not known statically."}

一些代碼:

類:

 public class ParentClass 
{ 
    public int ID { get; set; } 
    public string Name {get;set;} 
    public virtual List<ChildrenClass> Children { get; set; } 

} 

public class ChildrenClass 
{ 
    public int ID { get; set; } 
    public string MyProperty { get; set; } 
} 

服務:

[ServiceContract] 
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Required)] 
[ServiceBehavior(IncludeExceptionDetailInFaults = true)] 
public class MyService 
{ 

    static MyContext db; 
    public MyService() { db = new MyContext(); } 


    [WebGet(UriTemplate = "")] 
    public List<ParentClass> GetParents() 
    { 
     var result = db.Parents.ToList(); 
     return result; 

    } 

callinh這項服務的時候我不會得到結果。我究竟做錯了什麼?

回答

12

我不得不DisableProxyCreation在上下文配置:

[OperationContract] 
[WebGet(UriTemplate = "")] 
public List<ParentClass> GetParents() 
{ 
    using (DBContext context = new DBContext()) 
    { 
     context.Configuration.ProxyCreationEnabled = false; 
     List<ParentClass> parents = context.Parents 
      .Include("Children") 
      .ToList(); 
     return parents; 
     } 
} 

這工作得很好了我。

+0

正是我在找的。你知道禁用這個的缺點嗎? – hooked82

+1

代理有很多好處,記錄更新等。忘記包含語句沒有錯誤。我還沒有序列化proxi實體的解決方案 –

0

它似乎是序列化你的POCO的代理類,我的第一個建議是使用proxydatacontractresolver:http://msdn.microsoft.com/en-us/library/system.data.objects.proxydatacontractresolver.aspx

另外我想在具有發送過Web服務加載數據時,事情闡明瞭明確的工作......即

更改父類

public class ParentClass 
{ 
    public int ID { get; set; } 
    public string Name {get;set;} 
    public List<ChildrenClass> Children { get; set; } 

} 

改變你的內容關閉延遲加載: Disable lazy loading by default in Entity Framework 4

並且明確指定在通過線路發送數據時要加載的內容。

[WebGet(UriTemplate = "")] 
public List<ParentClass> GetParents() 
{ 
    var result = db.Parents.Include("Children").ToList(); 
    return result; 

} 

看看以下回答:Entity Framework Code First - Eager Loading not working as expected?更高級的包括調用。

此外,從經驗的建議,我不會通過網絡返回您的數據類,因爲它們爲您的Web服務的消費者形成合同。您最好有另一套您將數據值映射到的類。

這樣,如果您的數據類更改,您不必更改Web服務客戶端,除非明確要求。

如果您期望Parent或Child類中的行數爲1000,否則使用分頁很重要,否則您最終會選擇N + 1,請參閱:What is SELECT N+1?

+1

我試過DataContractResolver,但沒有幫助。 disableproxycreation確實有幫助。但是,如果我理解正確,我應該將從數據庫填充的POCO從服務中使用的類中分離出來。但這並不意味着每個對象都需要被複制,這意味着在該站點中使用的ParentClass和業務邏輯以及用於該服務中的單獨的ParentClass。那不是太多重複的代碼? – Mounhim

+0

我們使用DTO和Automapper將我們的資源模型與我們的域模型分開。這有很多優點,包括單獨的驗證和單獨的/不同的結構 – suing

+0

複製你的POCOs用於N種不同的用途往往是矯枉過正,包括疊加工作和維護maps/xlats。許多開發人員採取一次小心定義POCO的方法,然後將其用於數據傳輸和數據訪問,特別是在較小的項目中。如果有一段時間這不再起作用(模式更改,重構等),那麼應該定義新的POCO並根據需要執行映射。這種轉換/重構根本不影響Web客戶端,這對於類庫的.NET使用者來說只是一個問題。例如。二進制依賴。 –

0

在某些情況下,一個簡單的解決方案是使用包裝類,以便所有暴露的屬性都是已知類型。

通常,您的控制器類中不會使用ObjectContext或DbContext,因此在較早的圖層(業務或服務層)中,您可以快速轉換來自數據庫的對象到ViewModel樣式對象,類似於你在MVC應用程序中所做的,但不是將它們傳遞給View,而是將它們返回給調用者。

也許你不能在所有情況下使用它,但往往這是一個可行的妥協。