2014-02-11 45 views
9

使用實體框架6.0.2.NET 4.5.1的Visual Studio 2013更新1與連接到SQL Server的一個DbContext「跳過」方法僅支持LINQ to Entities中的排序輸入。該方法 '排序依據' 必須調用該方法之前, '跳過'

我有一個很長的過濾器鏈,我正在應用到基於調用者的期望結果的查詢。一切都很好,直到我需要添加分頁。這裏是一個一瞥:

IQueryable<ProviderWithDistance> results = (from pl in db.ProviderLocations 
              let distance = pl.Location.Geocode.Distance(_geo) 
              where pl.Location.Geocode.IsEmpty == false 
              where distance <= radius * 1609.344 
              orderby distance 
              select new ProviderWithDistance() { Provider = pl.Provider, Distance = Math.Round((double)(distance/1609.344), 1) }).Distinct(); 

if (gender != null) 
{ 
    results = results.Where(p => p.Provider.Gender == (gender.ToUpper() == "M" ? Gender.Male : Gender.Female)); 
} 

if (type != null) 
{ 
    int providerType; 
    if (int.TryParse(type, out providerType)) 
     results = results.Where(p => p.Provider.ProviderType.Id == providerType); 
} 

if (newpatients != null && newpatients == true) 
{ 
    results = results.Where(p => p.Provider.ProviderLocations.Any(pl => pl.AcceptingNewPatients == null || pl.AcceptingNewPatients == AcceptingNewPatients.Yes)); 
} 

if (string.IsNullOrEmpty(specialties) == false) 
{ 
    List<int> _ids = specialties.Split(',').Select(int.Parse).ToList(); 

    results = results.Where(p => p.Provider.Specialties.Any(x => _ids.Contains(x.Id))); 
} 

if (string.IsNullOrEmpty(degrees) == false) 
{ 
    List<int> _ids = specialties.Split(',').Select(int.Parse).ToList(); 

    results = results.Where(p => p.Provider.Degrees.Any(x => _ids.Contains(x.Id))); 
} 

if (string.IsNullOrEmpty(languages) == false) 
{ 
    List<int> _ids = specialties.Split(',').Select(int.Parse).ToList(); 

    results = results.Where(p => p.Provider.Languages.Any(x => _ids.Contains(x.Id))); 
} 

if (string.IsNullOrEmpty(keyword) == false) 
{ 
    results = results.Where(p => 
     (p.Provider.FirstName + " " + p.Provider.LastName).Contains(keyword)); 
} 

這是我加入的底部(skipmax只是INT參數)分頁:

if (skip > 0) 
    results = results.Skip(skip); 

results = results.Take(max); 

return new ProviderWithDistanceDto { Locations = results.AsEnumerable() }; 

現在我的問題(S):

  1. 正如你所看到的,我在最初的LINQ查詢中做了order by,所以wh是否它抱怨我需要做OrderBy之前做一個Skip(我以爲我是?)...

  2. 我假設它不會變成一個SQL查詢並執行,直到我枚舉結果,這就是爲什麼我等到最後一行返回結果AsEnumerable()。這是正確的方法嗎?

  3. 如果我必須在做SkipTake之前列舉結果,這將如何影響性能?很顯然,我想讓SQL Server完成繁重的工作,並只返回請求的結果。或者沒有關係(或者我錯了)?

回答

11

我做在初始LINQ查詢的排序依據,那麼,爲什麼抱怨,我需要做一個跳過前做一個排序依據(我想我是?)

result作爲有序查詢正確啓動:從第一行查詢返回的類型爲IOrderedQueryable<ProviderWithDistance>,因爲您有一個order by子句。但是,在它上面添加Where將使您的查詢再次成爲普通的IQueryable<ProviderWithDistance>,從而導致您在路上看到的問題。從邏輯上講,這是一回事,但內存中查詢定義的結構意味着其他方面。

要解決這個問題,在原有的查詢中刪除order by,並添加你是對之前準備好分頁,像這樣:

... 
    if (string.IsNullOrEmpty(languages) == false) 
     ... 
    if (string.IsNullOrEmpty(keyword) == false) 
     ... 
    result = result.OrderBy(r => r.distance); 

只要順序是最後的操作,這樣就可以解決運行時問題。

我的假設下,它不會變成一個SQL查詢和執行,直到我列舉的結果,這就是爲什麼我一直等到最後一行返回結果AsEnumerable()。這是正確的方法嗎?

是的,這是正確的做法。您希望您的RDBMS做盡可能多的工作越好,因爲在內存中做分頁失敗分頁擺在首位的目的。

如果我在做之前必須列舉結果跳過並考慮如何影響性能?

這會導致性能下降,因爲系統需要移動更多的數據,而不是添加分頁之前。

+0

快速註釋:如果您使用的是「開關」語句來處理你的中將sortOrder,請嘗試使用「默認」的情況下,將責令你的結果由您選擇的字段設置。 – CodeBreaker

相關問題