首页 > 解决方案 > 在 EF Core 中选择分组项目

问题描述

这在 EF 6.4 中有效:

from a in Addresses
group a by new {a.StreetName, a.StreetNumber} into agrp
where agrp.Count() > 3
from aitem in agrp
select aitem

如果 EF Core 5 我得到:

InvalidOperationException:无法翻译 LINQ 表达式“agrp => agrp”。以可翻译的形式重写查询,或通过插入对“AsEnumerable”、“AsAsyncEnumerable”、“ToList”或“ToListAsync”的调用显式切换到客户端评估。有关详细信息,请参阅https://go.microsoft.com/fwlink/?linkid=2101038

为什么?有没有不同的方法来写这个?

标签: entity-frameworkentity-framework-corelinq-to-entities

解决方案


如果您同意将数据加载到内存中,一个简单的解决方案可能是添加.ToList().AsEnumerable()之后Addresses

from a in Addresses.ToList() // or .AsEnumerable()
group a by new {a.StreetName, a.StreetNumber} into agrp
where agrp.Count() > 3
from aitem in agrp
select aitem

请注意,这(在 SqlServer 中)转换为:

SELECT [a].[Id], [a].[StreetName], [a].[StreetNumber]
FROM [Addresses] AS [a]

在 EF Core 中,GroupBy(在许多情况下)不翻译为 SQL,而是在内存中运行。(为避免意外将大量数据加载到内存中,EF 将抛出异常,除非.ToList()或被.AsEnumerable()调用以表明这是故意的。)

(...) 由于没有数据库结构可以表示IGroupingGroupBy因此在大多数情况下,运算符没有翻译。当聚合运算符应用于每个返回标量的组时,可以将其转换为GROUP BY关系数据库中的 SQL。(...)

-复杂的查询运算符,GroupBy

该文章还有一个查询示例,该示例可以转换为group by带有过滤器的查询Count(包括在下面)。不幸的是,该示例并未完全涵盖问题中的示例。它不会返回相关的地址对象,只返回分组键和计数。

var query = from p in context.Set<Post>()
            group p by p.AuthorId into g
            where g.Count() > 0
            orderby g.Key
            select new
            {
                g.Key,
                Count = g.Count()
            };
SELECT [p].[AuthorId] AS [Key], COUNT(*) AS [Count]
FROM [Posts] AS [p]
GROUP BY [p].[AuthorId]
HAVING COUNT(*) > 0
ORDER BY [p].[AuthorId]

推荐阅读