2013-09-23 63 views
2

我執行使用實體框架的服務器端分頁,並有下面的代碼LINQ到實體排序依據評估時的KeySelectors傳遞

DbQuery<T> query = Context.Set<T>(); 

query = IncludeNavigationProperties(query, includedProperties); 

var result = query.OrderBy(arg => arg.DatabaseId) 
        .Skip((pageNumber - 1)*pageSize) 
        .Take(pageSize).ToList(); 

產生我僅查詢所需數據的SQL(使用SQL查詢檢查早Server事件探查器)

SELECT TOP (21) 
[Extent1].[DatabaseId] AS [DatabaseId], 
...[other props here]... 
FROM (SELECT [Extent1].[DatabaseId] AS [DatabaseId], ...[other props here]..., row_number() OVER (ORDER BY [Extent1].[DatabaseId] ASC) AS [row_number] 
    FROM [dbo].[Table] AS [Extent1] 
) AS [Extent1] 
WHERE [Extent1].[row_number] > 84 
ORDER BY [Extent1].[DatabaseId] ASC 

於是我決定重新使用更多的情況下,這方法並傳遞keySelector作爲一個外部變量:

DbQuery<T> query = Context.Set<T>(); 

query = IncludeNavigationProperties(query, includedProperties); 

var result = query.OrderBy(keySelector) 
        .Skip((pageNumber - 1)*pageSize) 
        .Take(pageSize).ToList(); 

其中

Func<T, int> keySelector = arg => arg.DatabaseId; 

但它突然產生下面的SQL查詢:

SELECT 
[Extent1].[DatabaseId] AS [DatabaseId], 
...[other props here]... 
FROM [dbo].[Table] AS [Extent1] 

其中,據我瞭解,查詢表所有數據,然後對其進行處理的服務器。

所以,我有2個問題:

  1. 爲什麼查詢變化?
  2. 我該如何修復它(能夠改變keySelector並只查詢必要的數據)?

回答

2

DbQuery<T>派生自IQueryable<T>IEnumerable<T>類。這兩個類都提供了OrderBy方法,其中一個區別是:OrderByIEnumerable上獲得Func<T1,T2>OrderBy,在IQueriable獲得Expression<Func<T1,T2>>參數。當您將keyselector作爲Func<T1,T2>對象傳遞給OrderBy方法時,您告訴編譯器:嘿!請使用在IEnumerable上定義的OrderBy方法。換句話說你的DbQuery<T>對象被鑄造到IEnumerable<T>而不是IQueriable<T>.這就是爲什麼所有的數據都被提取到客戶端,並且進一步的操作是在內存中完成的。

爲了解決這個問題,更改的keyselectorFunc<T1,TKey>類型Expression <Func<T1,TKey>>爲:

public IQueriable<T> YourMethodName<T, TKey>(Expression<Func<T,TKey>> keyselector) 
{ 
    DbQuery<T> query = Context.Set<T>(); 

    query = IncludeNavigationProperties(query, includedProperties); 

    var result = query.OrderBy(keySelector) 
         .Skip((pageNumber - 1)*pageSize) 
         .Take(pageSize).ToList(); 
    return result; 
}