3

EF首先使用代码,我正在尝试创建一个查询,该查询将根据特定列获得玩家的排名,here Seniority
这是一个可能是Players表格的示例(Rank不是表格的一部分,我需要从中推断出来Seniority):

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 的玩家(即从 player1 到 player12),然后对其进行分页;例如,每页最多包含 10 个元素的第一页(即从 player1 到 player10)。

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 to Entities 无法识别方法 'System.Linq.IQueryable 1[Models.BO.Ranking.PlayerRanking] SelectMany[IGrouping2,PlayerRanking](System.Linq.IQueryable 1[System.Linq.IGrouping2[System.Int32,Models.BO.Players.Player]], System.Linq.Expressions.Expression 1[System.Func3[System .Linq.IGrouping 2[System.Int32,Models.BO.Players.Player],System.Int32,System.Collections.Generic.IEnumerable1[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 = 2Rank 从 1 重新开始(即 player11 被标记为第 1 位而不是第 9 位)。

4

1 回答 1

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);
于 2017-03-04T14:36:22.903 回答