2013-08-20 29 views
11

我試圖創建實體框架列表的篩選方法,並更好地瞭解Expression<Func<...實體框架過濾器「表達式<Func鍵<T, bool>>」

我有一個這樣的測試功能。

public IQueryable<T> Filter<T>(IEnumerable<T> src, Expression<Func<T, bool>> pred) 
{ 
    return src.AsQueryable().Where(pred); 
} 

,如果我這樣做:

context.Table.Filter(e => e.ID < 500); 

或本:

context.Table.Filter(e => e.SubTable.Where(et => et.ID < 500).Count() > 0 && e.ID < 500); 

這一切運作良好。

但是,如果我這樣做:

context.Table.Filter(e => e.SubTable.Filter(et => et.ID < 500).Count() > 0 && e.ID < 500); 

或本:

context.Table.Where(e => e.SubTable.Filter(et => et.ID < 500).Count() > 0 && e.ID < 500); 

我收到一個錯誤。 LINQ to Entities does not recognize the method ...Filter...

爲什麼它在一種情況下,而不是在加法器?我應該在過濾器中更改哪些內容才能與相關表一起使用。 我更願意遠離其他外部圖書館,因爲我想知道它是如何工作的,並且能夠在將來的任何場景中使用它。

在前兩種情況下,篩選器正確運行在數據庫中。

回答

20

喬恩和蒂姆已經解釋了爲什麼它不起作用。

假設Filter中的過濾代碼不是微不足道的,您可以更改Filter,以便它返回EF可以轉換的表達式。

讓我們假設你有這樣的代碼:

context.Table.Where(x => x.Name.Length > 500); 

現在,您可以創建一個方法返回該表達式:

Expression<Func<YourEntity, bool>> FilterByNameLength(int length) 
{ 
    return x => x.Name.Length > length; 
} 

用法是這樣的:

context.Table.Where(FilterByNameLength(500)); 

的只要您可以通過,您在FilterByNameLength內建立的表情可以任意複雜它直接到Where

+0

通過大量的閱讀和試​​驗和錯誤我懷疑這是唯一的方法。它會像context.Table.Where(e => e.subTable.Any(MyFilter())); –

+0

@ Pedro.The.Kid:不,它不會。這個方法的結果需要傳遞給最外層的Where,因爲你傳遞給最外層Where的每個表達式並沒有被實際執行,而是被解釋了。 –

+0

我做了一個測試,這工作var filter = MyFilter(); context.Table.Where(e => e.subTable.AsQueryable()。Any(filter)); –

4

爲什麼它在一種情況下,而不是在加法器?

因爲EF並不真正「知道」您的Filter方法。它不知道它意味着什麼,所以它不知道如何將它翻譯成SQL。與Where等相比,確實對有所瞭解。

,你叫它直接初始表版本的作品,因爲你不包含呼叫Filter表達式樹落得這樣 - 它只是調用Filter直接,這反過來又確實構建查詢一個查詢......但EF理解的一個查詢。

我會很驚訝,如果你能找出讓你Filter方法的EF查詢中工作的方式...但你已經說過,使用Where作品,無論如何,所以爲什麼要用Filter呢?我會用Where版本 - 或者更好的是,使用Any過載,這需要斷言:

context.Table.Filter(e => e.SubTable.Any(et => et.ID < 500) && e.ID < 500); 
+0

是否有任何方式可以改變,結束與一個表達樹女巫劑量不包括方法名稱? –

+0

@ Pedro.The.Kid:不容易。你可以編寫一個重寫表達式樹的方法,並基於這個方法創建一個新的查詢,但目前還不清楚爲什麼你會這麼做,這很棘手。 –

+0

至於使用哪裏它只是爲了方便在真實環境中測試它會複雜得多。 –

6

瞭解Expression<Func<>>Func<>之間的區別是很有益的。

一個Expressione => e.ID < 500商店關於表達的信息:那有一個Te,你所訪問的屬性ID,調用<運營商與int500。當EF着眼於此時,它可能會變成類似[SomeTable].[ID] < 500的東西。

Funce => e.ID < 500是一種方法等效於:

static bool MyMethod(T e) { return e.ID < 500; } 

它被編譯爲IL代碼的執行此;它不是被設計爲'重新構造成SQL查詢或其他任何東西,只能運行。

當EF採用您的Expression時,它必須理解它的每一部分,因爲它使用它來構建SQL查詢。它被編程爲知道現有的Where方法的含義。它不知道你的方法意味着什麼,即使它是一個微不足道的方法,所以它只是放棄了。

相關問題