Как получить индекс 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.IQueryable
1[Models.BO.Ranking.PlayerRanking] SelectMany[IGrouping
2, PlayerRanking] (System.Linq.IQueryable1[System.Linq.IGrouping
2 [System.Int32, Models.BO.Players.Player]], System.Linq.Expressions.Expression1[System.Func
3 [System.Linq.IGrouping2[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 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);