<T> 在 GroupBy() 之后展平 IQueryable 时出错



>我正在尝试从数据库中获取扁平化的对象,但出现错误。我想在数据库中获取 2 本所有类型的书,代码如下所示:

IQueryable<Book> query = _context.Books
.GroupBy(b => b.Genre)
.SelectMany(bc => bc.Select(b => b).Take(2));

有谁知道我在这里做错了什么?

我得到这个异常而不是结果:

无法翻译 LINQ 表达式"bc => bc .AsQueryable() .Select(b => b) .Take(2)"。以可翻译的形式重写查询,或通过插入对"AsEnumerable"、"AsAsyncEnumerable"、"ToList"或"ToListAsync"的调用来显式切换到客户端评估。有关详细信息,请参阅 go.microsoft.com/fwlink/?linkid=2101038。

我也尝试了类似的东西:

IQueryable<Book> query = _context.Genres.GroupJoin(
_context.Books,
g => g,
b => b.Genre,
(g, books) => new
{
Genre = g,
BookCollection = books
}
).SelectMany(bc => bc.BookCollection.Select(b => b)
.Take(2)).Include(b => b.Author).Include(b => b.Rating)
.Include(b => b.BookISBNs).Include(b => b.Reviews)
.ThenInclude(r => r.User);

此尝试将远离分组依据,这在数据库和 EF 查询转换中受到限制。相反,我们要进行子查询。

var genres = _context.Books.Select(b => b.Genre).Distinct();
var books =
from genre in genres
from book in _context.Books.Where(b => b.Genre == genre).Take(2)
select book;
var results = books.ToArrayAsync();

针对这种翻译:

SELECT c.*
FROM
(SELECT DISTINCT Genre FROM Books) as a,
(SELECT top 2 b.* FROM Books b WHERE b.Genre = a.Genre) as c

因此,您希望按GenreBook实体进行分组,然后从每个组中获取包含两本书的书籍的平面列表。我认为您无法使用实体框架可以转换为 SQL 的LINQ查询来表达GroupBy()

但这不是EF的错或缺点。 SQL 中的GROUP BY仅限于返回分组键和/或对组执行的任何聚合。例如,您可以按Genre对书籍进行分组,然后想要每组的类型和书籍总数 -

var result = dbCtx.Books
.GroupBy(p => p.Genre)
.Select(g => new
{
Genre = g.Key,       // grouping key
Count = g.Count()    // aggregation on group
})
.ToList();

EF 可以为此生成 SQL -

SELECT [b].[Genre] AS [Key], COUNT(*) AS [Count]
FROM [Books] AS [b]
GROUP BY [b].[Genre]

此参考可能会有所帮助 - 分组依据

由于没有数据库结构可以表示 IGrouping,因此 GroupBy 在大多数情况下,运算符没有翻译。当聚合 运算符应用于每个组,返回一个标量,它可以 在关系数据库中转换为 SQL GROUP。SQL 组依据 也是限制性的。它要求您仅按标量值进行分组。 投影只能包含分组键列或任何聚合 应用于列。

因此,对于您的查询,您必须获取书籍并在客户端进行分组,例如 -

var result = dbCtx.Books.AsEnumerable()
.GroupBy(p => p.Genre)
.SelectMany(g => g.Select(book => book).Take(2).ToList())
.ToList();

最新更新