[英]How to use Linq or Lambda with IQueryable to GroupBy and get the first/last record on the collection in C#?
我正在使用實體框架核心 3.1 連接到數據庫,我正在嘗試獲取按類別 ID 分組的最高和最低產品詳細信息。 根據這個問題和這個問題上顯示的答案,我嘗試編寫以下代碼:
使用 Linq:
//NOTE: 'Products' is an IQueryable for all the products in the database.
var highPrice = from a in Products
group a by a.CategoryId
into prods
select prods.OrderByDescending(a => a.Price).First();
使用 Lambda:
//NOTE: 'Products' is an IQueryable for all the products in the database.
var highPrice = Products.GroupBy(a => a.CategoryId, (key, a) => a.OrderByDescending(a => a.Price).First()).ToList();
僅當我使用例如.ToList()
將Products
的IQueryble
轉換為IEnumerable
時,兩者都可以正常工作,但是在不進行轉換的情況下運行時,它會彈出以下異常:
System.InvalidOperationException
HResult=0x80131509
Message=The LINQ expression '(GroupByShaperExpression:
KeySelector: (a.CategoryId),
ElementSelector:(EntityShaperExpression:
EntityType: Product
ValueBufferExpression:
(ProjectionBindingExpression: EmptyProjectionMember)
IsNullable: False))
.OrderByDescending(a => a.Price)' could not be translated. Either rewrite the query in a form that can be translated, or switch to client evaluation explicitly by inserting a call to either AsEnumerable(), AsAsyncEnumerable(), ToList(), or ToListAsync().
有沒有辦法在不轉換為 IEnumerable 的情況下獲取 IQueryable 集合的第一條/最后一條記錄?
並非所有 Linq 方法都可以轉換為 SQL 查詢(這就是您的表達式無法編譯的原因)。
因此,您可以使用 Take() 方法結合 order by 子句獲得相同的結果。 按照你的例子:
var mostExpensiveProductByCategory = dbContext.Products
.GroupBy(x => x.CategoryId).Select(x => new
{
CategoryId = x.Key,
Product = x.OrderByDescending(p => p.Price).Take(1)
})
.ToList();
var cheapestProductByCategory = dbContext.Products
.GroupBy(x => x.CategoryId).Select(x => new
{
CategoryId = x.Key,
Product = x.OrderBy(p => p.Price).Take(1)
})
.ToList();
更新:
為了實現您的要求並避免內存中分組,我建議您使用導航屬性,請參見下文:
var mostExpensiveProductByCategory = dbContext.Categories.Select(x => new
{
x.CategoryId,
Products = x.Products.OrderByDescending(p => p.Price).Take(1)
}).ToList();
這將產生以下查詢 output:
SELECT [c].[CategoryId], [t0].[ProductId], [t0].[CategoryId], [t0].[Price]
FROM [Categories] AS [c]
LEFT JOIN ( SELECT [t].[ProductId], [t].[CategoryId], [t].[Price]
FROM ( SELECT [p].[ProductId], [p].[CategoryId], [p].[Price], ROW_NUMBER() OVER(PARTITION BY [p].[CategoryId] ORDER BY [p].[Price] DESC) AS [row]
FROM [Products] AS [p] ) AS [t] WHERE [t].[row] <= 1 ) AS [t0] ON [c].[CategoryId] = [t0].[CategoryId]
ORDER BY [c].[CategoryId], [t0].[CategoryId], [t0].[Price] DESC, [t0].[ProductId]
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.