我有2张 table :

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 内或者是 SUM 的属性。这个例子非常简单,因为我不仅有 Name,还有 User 表中的其他属性。

我该如何解决这个问题?

最佳答案

它需要很长时间,因为查询导致 client evaluation 。请参阅 Client evaluation performance issues 以及如何使用 Client evaluation logging 来识别相关问题。

如果您真的在使用 EF Core 2.0,那么除了升级到包含改进的 LINQ GroupBy translation 的 v2.1 之外,您无能为力。即使有了它,解决方案也不是直截了当的 - 查询仍然使用客户端评估。但是可以通过将 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();

这仍然会产生警告



但至少查询被翻译并作为单个 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]

关于c# - EF Core 2.0 按其他属性分组,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/53305197/

10-13 06:06
查看更多