>我正在尝试从数据库中获取扁平化的对象,但出现错误。我想在数据库中获取 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
因此,您希望按Genre
对Book
实体进行分组,然后从每个组中获取包含两本书的书籍的平面列表。我认为您无法使用实体框架可以转换为 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();