EF Core 2.0 Group По другим свойствам - PullRequest
0 голосов
/ 14 ноября 2018

У меня есть 2 таблицы:

USERS
UserId
Name
Scores (collection of table Scores)

SCORES
UserId
CategoryId
Points

Мне нужно показать всем пользователям и СУММУ их баллов, но также мне нужно показать имя пользователя. Может быть отфильтровано по CategoryId или нет.

Context.Scores
.Where(p => p.CategoryId == categoryId) * OPTIONAL
.GroupBy(p => p.UserId)
.Select(p => new 
{
    UserId = p.Key,
    Points = p.Sum(s => s.Points),
    Name = p.Select(s => s.User.Name).FirstOrDefault()
}).OrderBy(p => p.Points).ToList();

Проблема в том, что когда я добавляю

Name = p.Select(s => s.User.Name).FirstOrDefault()

Это занимает так много времени. Я не знаю, как получить доступ к свойствам, которые не находятся внутри GroupBy или являются суммой. Этот пример очень прост, потому что у меня есть не только имя, но и другие свойства из таблицы пользователей.

Как я могу решить это?

1 Ответ

0 голосов
/ 14 ноября 2018

Это занимает столько времени, потому что запрос вызывает оценку клиента .См. Проблемы производительности оценки клиента и как использовать Ведение журнала оценки клиента для выявления связанных проблем.

Если вы действительно используете EF Core 2.0, вы ничего не можете сделатьчем обновление до версии 2.1, которая содержит улучшенный перевод LINQ GroupBy .Даже с этим решение не простое - запрос все еще использует оценку клиента.Но его можно переписать, разделив часть GroupBy на подзапрос и присоединив ее к таблице Users, чтобы получить необходимую дополнительную информацию.

Примерно так:

var scores = db.Scores.AsQueryable();
// Optional
// scores = scores.Where(p => p.CategoryId == categoryId);

var points = scores
     .GroupBy(s => s.UserId)
     .Select(g => new
     {
         UserId = g.Key,
         Points = g.Sum(s => s.Points),
     });

var result = db.Users
    .Join(points, u => u.UserId, p => p.UserId, (u, p) => new
    {
        u.UserId,
        u.Name,
        p.Points
    })
    .OrderBy(p => p.Points)
    .ToList();

Thisпо-прежнему выдает предупреждение

Выражение LINQ 'orderby [p] .Points asc' не может быть переведено и будет оценено локально.

, но по крайней мере запроспереводится и выполняется как один SQL:

SELECT [t].[UserId], [t].[Points], [u].[UserId] AS [UserId0], [u].[Name]
FROM [Users] AS [u]
INNER JOIN (
    SELECT [s].[UserId], SUM([s].[Points]) AS [Points]
    FROM [Scores] AS [s]
    GROUP BY [s].[UserId]
) AS [t] ON [u].[UserId] = [t].[UserId]
...