Как получить индекс IGrouping с Linq для сущностей? (NotSupportedException)

Я использую EF сначала код, и я пытаюсь создать запрос, который бы получил рейтинг игрока на основе определенного столбца, здесь 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.IQueryable1[Models.BO.Ranking.PlayerRanking] SelectMany[IGrouping2, PlayerRanking] (System.Linq.IQueryable1[System.Linq.IGrouping2 [System.Int32, Models.BO.Players.Player]], System.Linq.Expressions.Expression1[System.Func3 [System.Linq.IGrouping2[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 to player10 с правильными рангами:)
Однако для pageNb = 2 ранг снова начинается с 1 (т.е. игрок11 помечается как 1-й, а не 9-й).

1 ответ

Решение

Linq to Entities не поддерживает перегрузки методов с index, Кроме того, поскольку любое использование GroupBy возвращающая последовательность (а не просто ключи + агрегаты, как в SQL GROUP BY) приводит к 2 путям доступа к таблице в сгенерированном SQL, вы можете просто сделать это вручную и использовать 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);
Другие вопросы по тегам