2013-03-28 42 views
2

我正在使用EF 5和ASP.NET Web API從控制器返回JSON。我的例子是一個寵物服務。對於這個問題,實體是Client,PetVeterinarian。的關係是:EF,ASP.NET Web API和JSON.NET - 返回限制層次結構

客戶端=>一個一對多=>寵物=>一到一個=>獸醫

,並扭轉層次:

獸醫=>一個一對多=>寵物=>一到一個=>客戶端

在我PetsController,該GetPets動作看起來像這樣:

var pets= db.Pets 
    .Where(p => p.IsActive == true) 
    .Include(p => p.Client) 
    .Include(p => p.Veterinarian); 

return Mapper.Map<IEnumerable<Pet>, IEnumerable<PetDTO>>(pets); // Using Automapper to map to a DTO 

產生的JSON有寵物,每個寵物客戶端,每個寵物獸醫和每個獸醫,寵物的集合。

我明白爲什麼JSON會顯示寵物的集合,但它與控制器操作中的Pets列表無關(至少不是現在)。我正在尋找一種優雅的方式去除寵物的集合。現在,我使用的是什麼感覺就像一個黑客:

var pets= db.Pets 
    .Where(p => p.IsActive == true) 
    .Include(p => p.Client) 
    .Include(p => p.Veterinarian); 

foreach (Pet pet in pets) { 
    pet.Veterinarian.Pets = null; // Remove the Pets collection before serializing 
} 

return Mapper.Map<IEnumerable<Pet>, IEnumerable<PetDTO>>(pets); // Using Automapper to map 

我已經嘗試了一些事情串行和一些IQuerable方法(其中有許多我不熟悉),但無濟於事。

回答

1

您可以禁用延遲加載來修剪圖形。但這仍然不能解決問題。如果你有雙向關係(比如寵物< => Veterinarian),使用Include獲取關係的一面也會自動構建另一面。因此,即使您沒有在Include中明確詢問,您的查詢pet.Veterinarian.Pets也不會爲空。

使用DTO是我能想到的最佳方式。你完全控制了對象圖。

另外,OData協議有這個機制已經通過$ select & $ expand定義,並且給客戶機提供控制來指定它需要的對象圖的深度和寬度。例如,對於您的場景,OData網址將顯示爲~/Pets?$expand=Client,Veterinarian。你有沒有考慮OData的需求?

如果您不想每次創建DTO,都可以使用匿名對象實時創建。例如,對於您的場景,您可以這樣做,

db.Pets.Select(p => new 
{ 
    Id = p.ID, 

    .... other pet properties you want, 

    Veterinarian = new 
    { 
     ID = p.Veterinarian.ID 
     ... other veterinarian properties you want 
    }, 
    Client = 
    { 
     ... client properties you need. 
    } 

}); 

這只是將映射移動到select子句中。

+0

是的,但目前不支持OData $ expand選項[(在ASP.NET WebAPI OData中返回子元素)](http://stackoverflow.com/questions/14392402/returning-child-elements-in-asp -net-webapi-odata)這就是爲什麼我嘗試不同的方法。有時候我想要一個特定獸醫護理下的寵物列表,而不是當我要求一張寵物列表作爲圖表的根源時。而且我不想爲不同的「根對象」情況創建不同的DTO。 – user2220004

+0

您可以在選擇查詢中執行映射。我用樣本更新了答案。 –

+1

此外,我們剛剛開始在Web API OData中進行$ select和$ expand支持。它應該很快在我們的夜間建築中亮起來。 –