3

我一直在尋找這個問題很長一段時間。當Web API返回IQueryable時,EF引用會丟失

這是交易。 我正在構建一個調用Web API來獲取其數據的網站。我的Web API使用庫來處理存儲庫模式。我的數據庫模型(EF Model-first)建立在庫中。在那個模型中,我有一個基類Pass。然後我有兩個派生類,CustomerCard:Pass和Voucher:Pass。 My model from EF Designer

我有一個獲取所有CustomerCards的方法。

public IQueryable<CustomerCard> GetAllPasses() { 
     IList<CustomerCard> allCards = new List<CustomerCard>(); 

     var c_cards = context.Passes; 
     foreach (var c_card in c_cards) { 
      if (c_card is CustomerCard) { 
       allCards.Add((CustomerCard)c_card); 
      } 
     } 
     return allCards.AsQueryable<CustomerCard>(); 
    } 

在我ApiController,我用這個方法來獲得通行證,並退回給網站,像這樣的:

[HttpGet] 
    [Queryable] 
    public IQueryable<CustomerCard> GetAllPasses(string version) { 
     return passRepo.GetAllPasses().AsQueryable(); 
    } 

我的Web API返回JSON格式。這是我的配置保存參考和東西:

 var json = config.Formatters.JsonFormatter; 
     json.SerializerSettings.PreserveReferencesHandling = 
      Newtonsoft.Json.PreserveReferencesHandling.Objects; 
     json.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Serialize; 
     config.Formatters.Remove(config.Formatters.XmlFormatter); 

我使用IQueryable的,因爲我希望能夠到網頁上我的網站的數據。 api方法在'/ api/v1/passes/all'處可用。

這是奇怪的部分。爲了測試我的分頁,我打電話給每頁1次。 對於我的第一個通行證,它工作正常。但是當我進入第二頁時,他也得到了正確的通行證,但對用戶的引用已經消失。

正如您在my model中看到的那樣,CustomerCard類具有屬性User。這表明誰擁有該客戶卡。

所以這個調用加載從通用戶: 'API/V1 /通行證/所有$頂部= 1?' 但是當我打電話給這一個,用戶實例是NULL:「API/V1 /通過/全部?$ top = 1 & $ skip = 1'。

但是,當我打電話給'api/v1/passes/all?$ top = 2'時,第二遍用戶被加載。 所以這是我的頭腦被炸燬的地方!我不明白嗎?爲什麼沒有用戶引用與第二個一起?它可能與EF的延遲加載功能有關嗎?

EDIT 當我使用擴展方法包括上context.passes,則會引發錯誤:

A中規定的包含路徑是無效的。 EntityType'LCS_Model.Pass' 未聲明名爲'User'的導航屬性。

這是因爲通過作爲dbset,包含CustomerCard以及憑證。有什麼方法可以告訴我的上下文期望或將其轉換爲CustomerCard?

有人可以幫助我。如果你不明白我的問題,就問問吧!

謝謝!

EDIT 2

的方法我API控制器上現在

[HttpGet] 
[Queryable] 
public IQueryable<CustomerCard> GetAllPasses(string version) { 
    return context.Passes.Include("User").OfType<CustomerCard>(); 
} 

這給了我正確的項目。我的數據庫中有2張客戶卡。兩者都來自同一個用戶。我的API有用戶仍然加載。在我的網站收到響應的那一刻,用戶屬性變爲空。我的猜測是,這是因爲它仍然從數組的第一個元素引用同一個用戶。那可能嗎?如果是的話,我該如何防止這種情況發生?

+0

您能否爲Method「all」添加控制器代碼? – 2013-04-09 14:17:42

+0

第二個代碼塊是控制器代碼。路徑'api/{version}/passes/all'路由到action =「GetAllPasses」。 – SandersD 2013-04-09 14:37:08

回答

2

是的,您需要確保在執行查詢時包含任何相關記錄。有關示例,請參閱this。其次......我不明白你爲什麼要用for循環做所有這些工作......如果你想做任何分頁,那麼這對服務器來說是絕對不必要的和浪費的工作。我在想,除了你可能想要應用的其他過濾器之外,你的GetAllPasses應該看起來像這樣。

public IQueryable<CustomerCard> GetAllPasses() { 
    return context.Passes.Include(r => r.User); 
} 

編輯(2):我需要讀得更好。我必須承認,我不熟悉EF中的類型繼承。我發現了一些可能在這裏工作的東西:table per hierarchy,table per concrete type,另請參閱MSDN Queryable.OfType<TResult>。這是一個猜測,但讓我們試試:

public IQueryable<CustomerCard> GetAllPasses() { 
    return context.Passes.OfType<CustomerCard>().Include(r => r.User); 
} 
+1

這也是我最初的解決方案。問題是我的EF模型只創建了一個dbset。 Users屬性僅適用於子類型CustomerCard(在我的db [dbo]。[Passes_CustomerCard]中生成的單獨表格。因此,當我想在Include中使用您的建議方法時,出現錯誤,指出用戶不是財產,這是我最大的問題,我可以告訴我的上下文,它需要從CustomerCard或什麼? – SandersD 2013-04-09 15:41:02

+0

它看起來像你可以,讓我知道如果這不起作用 – JayC 2013-04-09 16:17:12

+0

謝謝,我會嘗試第一件事在早上!我會讓你知道 – SandersD 2013-04-09 22:07:58

相關問題