实体框架 EF Core 异常"Unable to translate the given 'GroupBy' pattern"



>我使用 EFCore 5.0.12

我有以下实体:

public class Course {
public int Id { get; set; }
[Required]
public string Title { get; set; }
public string Description { get; set; }
public CourseLevel Level { get; set; }
[Column(TypeName = "decimal(7,2)")]
public decimal FullPrice { get; set; }
}

现在我尝试执行如下组查询:

var query3 =
from c in context.Courses
group c by c.Level
into g
select g;
foreach (var group in query3) {
Console.WriteLine($"{group.Key} ({group.Count()})");
foreach (var c in group) {
Console.WriteLine($"t{c.Title}");
}
}

这将生成异常

无法转换给定的"分组依据"模式。调用"可枚举" 在"GroupBy"之前,以在客户端对其进行评估。

为什么不能将其转换为sql?

数据库根本无法产生由普通 LINQGroupBy生成的结果 .
数据库和 LINQ 都使用不同形式的分组。
与 LINQ 分组相反,数据库有更严格的规则:分组必须始终与聚合函数一起使用,如Count()Sum()Avg()Min()Max()

示例
给定是下表

Users
-------------------------
| age | name  | lastname |
-------------------------
| 27  | Nancy | Doe
| 27  | Nancy | Apple
| 65  | Bob   | Uncle
| 27  | Bob   | Doe
| 35  | Bob   | Marley
| 27  | Jim   | Beam
--------------------------

常见的 LINQ 查询是:

"获取按age分组的所有Users记录"。

Users.GroupBy(user => user.Age);

结果是一组元首,其中keyagevalueUser.Age等于(key, {...})User实例的集合:

(27, {User, User, User, User})
(65, {User})
(35, {User})

上面的结果显示了数据库分组的局限性:不可能使数据库返回这样的结果。数据库不能返回列表或数组 - 它只返回行和列。因此,此类查询无法转换为 SQL 或由数据库执行,因此 EF 会引发异常以通知客户端此不便。
此问题的解决方案是在数据库上下文之外的客户端显式执行分组,或修复表达式以满足上述有效数据库分组规则。

有效的 SQL 查询为:

"获取按name分组的age'27'的用户数。">

SELECT Count(age), name FROM Users WHERE age=27 GROUP BY name

结果是一组元组,其中key是具有相同年龄的用户的countvalue这些用户的name(age_count, name)

(2, Nancy)
(1, Bob)
(1, Jim)

如果 LINQ 查询也使用聚合函数,则可以毫无问题地将查询转换为 SQL。 为了生成上述 SQL 查询结果,我们可以编写:

dbContext.Users
.GroupBy(
user => user.Name, 
(name, users) => new { Count = users.Count(user => user.Age == 27), name });

from user in dbContext.Users
group user by user.Name
into groups 
select new { Count = groups.Count(user => user.Age == 27), groups.Key };

你不能直接循环IGrouping(当然,如果你正在构建一个IQueryable),文档解释说:

此外,IGrouping实现了IEnumerable<TElement>,这意味着您可以在分组后使用任何 LINQ 运算符对其进行撰写。因为没有数据库结构可以表示IGroupingGroupBy算子在大多数情况下没有翻译。当聚合运算符应用于每个返回标量的组时,可以将其转换为关系数据库中的 SQLGROUP BY

相关内容

最新更新