简体   繁体   English

实体框架 EF Core 异常“无法转换给定的‘GroupBy’模式”

[英]Entity Framework EF Core exception "Unable to translate the given 'GroupBy' pattern"

I use EFCore 5.0.12我使用 EFCore 5.0.12

I have the following Entity:我有以下实体:

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; }
}

Now I try to do a group-query like:现在我尝试做一个组查询,如:

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}");
   }
}

This generates the Exception这会产生异常

Unable to translate the given 'GroupBy' pattern.无法翻译给定的“GroupBy”模式。 Call 'AsEnumerable' before 'GroupBy' to evaluate it client-side.在“GroupBy”之前调用“AsEnumerable”以在客户端对其进行评估。

Why can this not be translated to sql?为什么这个不能翻译成sql?

You cannot directly loop over an IGrouping (if you are building an IQueryable of course), the documentation explains that:您不能直接遍历IGrouping (当然,如果您正在构建IQueryable ), 文档解释说:

Furthermore, IGrouping implements IEnumerable<TElement> , which means you can compose over it using any LINQ operator after the grouping.此外, IGrouping实现了IEnumerable<TElement> ,这意味着您可以在分组后使用任何 LINQ 运算符对其进行组合。 Since no database structure can represent an IGrouping , GroupBy operators have no translation in most cases .由于没有任何数据库结构可以表示IGrouping ,因此GroupBy运算符在大多数情况下没有翻译 When an aggregate operator is applied to each group, which returns a scalar, it can be translated to SQL GROUP BY in relational databases.当聚合运算符应用于每个组时,返回一个标量,它可以转换为关系数据库中的 SQL GROUP BY

A database simply can't produce a result that is produced by a plain LINQ GroupBy .数据库根本无法产生由普通 LINQ GroupBy产生的结果。
Both, database and LINQ use a different form of grouping.数据库和 LINQ 都使用不同的分组形式。
Opposed to LINQ grouping, databases have stricter rules: grouping must always be used with an aggregation function like Count() , Sum() , Avg() , Min() or Max() .与 LINQ 分组相反,数据库有更严格的规则:分组必须始终与聚合函数一起使用,如Count()Sum()Avg()Min()Max()

Example例子
Given is the following table给出的是下表

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

A common LINQ query would be:一个常见的 LINQ 查询是:

"Get all Users records grouped by age ". “获取按age分组的所有Users记录”。

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

Result is a set of tupels where the key is the age and the value a collection of User instances where User.Age is equaL (key, {...}) :结果是一组元组,其中keyagevalueUser.AgeUser.Age (key, {...})User实例集合:

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

The above result shows the limitations of database grouping: it is not possible to make a database return such a result.上面的结果说明了数据库分组的局限性:不可能让一个数据库返回这样的结果。 A database can't return lists or arrays - it only returns rows and columns.数据库不能返回列表或数组——它只返回行和列。 Therefore, such a query can't be translated to SQL or executed by a database, hence EF throws an exception to notify the client about this inconvenience.因此,此类查询无法转换为 SQL 或由数据库执行,因此 EF 会抛出异常以通知客户端此不便。
The solution to this problem would be to explicitly execute the grouping on the client-side, outside the database context, or to fix the expression to meet the aforementioned rules for valid database grouping.此问题的解决方案是在客户端、数据库上下文之外显式执行分组,或者修复表达式以满足上述有效数据库分组规则。

A valid SQL query would be:一个有效的 SQL 查询是:

"Get the number of users that are of age '27' grouped by name ." “获取按name分组的age '27' 的用户数量。”

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

Result is a set of tuples, where the key is the count of users with the same age and the value the name of those users (age_count, name) :结果是一组元组,其中key是相同年龄的用户countvalue是这些用户的name (age_count, name)

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

If the LINQ query uses an aggregation function too, the query can be translated to SQL without any problems.如果 LINQ 查询也使用聚合函数,则该查询可以毫无问题地转换为 SQL。 To produce the above result of the SQL query we can write:要生成 SQL 查询的上述结果,我们可以编写:

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

Or或者

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM