2017-04-12 36 views
0

我有一個應用程序使用EF 6和MVC 5,適用於輸入數據,但現在當我嘗試顯示它的一些我有麻煩。我的實體的基本佈局可以看到如下圖:如何在EF 6和MVC 5中查詢和顯示子孫數據?

entity layout

在那裏我遇到問題的第一部分是在查詢和篩選數據。我希望返回一份調查和簽收存在的房屋和相關數據清單,但批准不會。在直SQL,即現在的工作查詢是:

SELECT * 
FROM Premises p LEFT OUTER JOIN Approvals a ON a.Id = p.Id 
JOIN Surveys s ON s.PremiseId = p.Id 
JOIN SignOffs so ON so.Id = s.Id 
WHERE a.ApprovedBy IS NULL 

,我開始用的代碼是這樣的:

var premises = Premises.Include(p => p.Approval) 
    .Include(p => p.Surveys) 
    .Include(p => p.Surveys.Select(s => s.SignOff)); 

出現 *返回所有記錄,包括孩子的數據,但當我嘗試對其進行過濾時,我只收到具有簽收記錄但沒有批准的記錄,但不起作用。

var premises = Premises.Include(p => p.Approval).Where(p => p.Approval.ApprovedBy == null) 
    .Include(p => p.Surveys) 
    .Include(p => p.Surveys.Select(s => s.SignOff).Where(s => s.Signature != null)); 

如果我用這個代碼,我得到這個錯誤:

包含路徑表達式必須引用的類型定義的導航屬性。對於參考導航屬性使用虛線路徑,對集合導航屬性使用Select運算符。 參數名稱:路徑

我已經改變了這個查詢周圍很多嘗試不同的東西,所以我不知道我所做的,但我認爲首先Where語句可能通過自身工作,但第二個肯定會導致錯誤。 如何構建我的查詢來讓它正確地返回請求的數據過濾?

此外,我在上面加星號表示查詢出現返回所有的數據和子數據,因爲我實際上不能測試它。當我試圖爲此編寫我的Razor CSHTML頁面時,它不會給我智能感知兒童和孫子的數據,如果我輸入我認爲應該的東西,我會得到錯誤。我如何需要在頁面上引用這些數據?

回答

1

你不能像這樣使用Include(),它只適用於指定加載導航屬性,而不是指定在導航屬性是什麼時加載實體(在你的情況下不是null)。

做過濾,我建議是這樣的:

var premises = Premises.Include(p => p.Approval).Include(p => p.Surveys).Include(p => p.Surveys.Select(s => s.SignOff)) 
       .Where(p=>p.Approval.ApprovedBy!=null && p.Surveys.Any(s=>s.SignOff.Signature!=null)); 

所以基本上,包括和過濾無關彼此。使用includes,只能指定要加載的內容,但仍可以在原始實體集上使用過濾器。

1

你很困惑什麼是LINQ方法Include。它只告訴EF急切地加載該關係,如果你的查詢本身利用這種關係,這實際上是不必要的;在這種情況下,EF將默認包含關係。

它沒有做的是讓你過濾這些關係。例如,在代碼中的這一部分:

.Include(p => p.Surveys.Select(s => s.SignOff).Where(s => s.Signature != null)); 

where子句應用於PremisesSignOff,你似乎認爲。換句話說,Where可以篩選被查詢的主表,而不是你所包含的表。

這裏有兩條路徑。你可以簡單地通過重要的部分,即過濾Premises

var premises = Premises.Where(p => p.Approval.ApprovedBy == null && p => p.Surveys.Any(s => s.SignOff.Signature != null)); 

,將返回只有當這些條件都爲真前提,但包括Surveys集合將包含所有調查涉及到每個前提下,不只是那些具有空簽名簽名。

如果您需要篩選相關項目,以及,那麼你必須明確地加載它們:注意

foreach (premise in premises) 
{ 
    context.Entry(premise) 
     .Collection(p => p.Surveys) 
     .Query() 
     .Where(s => s.SignOff.Signature != null) 
     .Load(); 
} 

兩件事情:

  1. 由於此查詢必須如何的性質應用,所有場所都無法做到這一點。您必須遍歷整個場所並明確加載每個集合的Surveys集合。

  2. 由於這將發出新的查詢,因此您希望避免在此explict加載之前延遲或急切地加載Surveys集合。否則,你會兩次查詢相同的信息,這是非常低效的。確保最簡單的方法是從集合屬性中刪除virtual關鍵字。但是,如果你這樣做,那麼你將不得不急切或顯式加載集合,否則它將爲空。欲瞭解更多信息,請參閱:https://msdn.microsoft.com/en-us/library/jj574232(v=vs.113).aspx

相關問題