3

我首先使用EF代碼,並且我試圖創建一個查詢,根據特定列獲得玩家等級,這裏是Seniority
下面是可能是什麼Players表爲例(Rank是不是它的一部分,我需要從Seniority推斷出這一點):如何獲得與Linq的實體的IGrouping索引? (NotSupportedException)

Username | Seniority (=> Rank) 
player1 | 25  (=> 1st) 
player2 | 20  (=> 2nd) 
player3 | 20  (=> 2nd) 
player4 | 18  (=> 3rd) 
player5 | 16  (=> 4th) 
player6 | 16  (=> 4th) 
player7 | 15  (=> 5th) 
player8 | 11  (=> 6th) 
player9 | 10  (=> 7th) 
player10 | 8   (=> 8th) 
player11 | 7   (=> 9th) 
player12 | 5   (=> 10th) 
player13 | 2   (=> 11th) 
player14 | 1   (=> 12th) 
player15 | 0   (=> 13th) 

我需要以下要求返回所有的玩家,其排名爲< = 10(即從玩家1到玩家12),然後分頁;例如每頁有10個最大元素的第一頁(即,從玩家1到玩家10)。

entities.Players 
.GroupBy(p => p.Seniority) 
.Where((group, groupIndex) => groupIndex <= 10) 
.SelectMany((group, groupIndex) => 
    group.Select(grp => 
     new PlayerRanking() 
     { 
      Player = grp, 
      Rank = groupIndex + 1, 
      Score = grp.Seniority 
     } 
    ) 
    .OrderByDescending(r => r.Score) 
    .ThenBy(r => r.Player.UserName) 
) 
.ToPagedList(pageNb, 10); 

LINQ實體無法識別方法「System.Linq.IQueryable 1[Models.BO.Ranking.PlayerRanking] SelectMany[IGrouping 2,PlayerRanking](System.Linq.IQueryable 1[System.Linq.IGrouping 2 [System.Int32,Models.BO.Players.Player]] ,System.Linq.Expressions.Expression 1[System.Func 3 [System.Linq.IGrouping 2[System.Int32,Models.BO.Players.Player],System.Int32,System.Collections.Generic.IEnumerable 1 [Models.BO.Ranking.PlayerRanking]]])',並且此方法無法轉換爲商店表達式。

我一些其他職位讀取EF抱怨Where並且具有兩個參數SelectMany,但我可以沒有?
我不想使用ToList()AsEnumerable(),因爲如果我這樣做,我想請求會枚舉所有Players條目(這可能真的很大......),儘管我只需要其中的10條。我真的關心這個特定查詢的表現。

有沒有辦法?

非常感謝。

@octavioccl

我剛添加的Skip一部分分頁:

var result = entities.Players.GroupBy(p => p.Seniority) 
         .OrderBy(e=>e.Key) 
         .Skip((pageNb - 1) * 10) 
         .Take(10) 
         .AsEnumerable() 
         .SelectMany((g,i)=>g.OrderBy(e=>e.UserName) 
              .Select(e=>new PlayerRanking() 
                 { 
                  Player = e, 
                  Rank = i + 1, 
                  Score = e.Seniority 
                 }); 

對於pageNb = 1,結果似乎是正確的,我有PLAYER1用正確的行列:)
到Player10的但是對於pageNb = 2,排名從1重新開始(即,玩家11被標記爲1而不是9)。

回答

2

Linq to Entities不支持index的方法重載。此外,因爲任何使用GroupBy返回序列(而不是簡單的鍵+聚合如SQL GROUP BY)導致生成的SQL中有2個表訪問路徑,您可以簡單地手動執行該操作,並使用Count方法確定排名(應該是不同的Seniority值的計數大於當前值)。

所以您的查詢的工作相當於可能是這樣的:

var result = entities.Players 
    .Select(p => new PlayerRanking 
    { 
     Player = p, 
     Rank = entities.Players.Where(p1 => p1.Seniority > p.Seniority) 
       .Select(p1 => p1.Seniority).Distinct().Count() + 1, 
     Score = p.Seniority 
    }) 
    .Where(r => r.Rank <= 10) 
    .OrderBy(r => r.Rank) 
    .ThenBy(r => r.Player.UserName) 
    .ToPagedList(pageNb, 10); 
+0

非常感謝,就像一個魅力!再一次,你讓我的一天,我學到了一些東西:D –

+0

不客氣。你所有的問題都很有趣且富有挑戰性:)不幸的是,沒有任何東西可以擊敗SQL ['OVER'](https://msdn.microsoft.com/en-us/library/ms189461。aspx)子句,但只是沒有等效的LINQ/EF構造。如果你有性能問題,你可以使用原始的SQL :) –

+2

不知道'OVER'子句,確實很酷,如果有必要,我一定會使用它!由於該應用還沒有真正的用戶,但我無法確定表演的效果,但至少我會在開發過程中考慮這一點。雖然這可能與這個問題沒有直接關係,但我會說真的很感謝你,因爲你花了很多時間幫助人們,包括我;) –