[英]EF Core 2.1 GROUP BY and select first item in each group
讓我們想象一個論壇,其中包含主題和帖子的列表。 我想獲取每個主題的主題列表和最后一篇文章的標題(按日期)。
有沒有辦法使用 EF Core (2.1) 來實現這一點? 在 SQL 中可以這樣做
SELECT Posts.Title, Posts.CreatedDate, Posts.TopicId FROM
(SELECT Max(CreatedDate), TopicId FROM Posts GROUP BY TopicId) lastPosts
JOIN Posts ON Posts.CreatedDate = lastPosts.CreatedDate AND Posts.TopicId = lastPosts.TopicId
在 EFCore 我可以 select LastDates
_context.Posts.GroupBy(x => x.TopicId, (x, y) => new
{
CreatedDate = y.Max(z => z.CreatedDate),
TopicId = x,
});
如果我 run.ToList() 查詢被正確翻譯為GROUP BY
。 但我不能進一步 go 。 以下在 memory 中執行,而不是在 SQL 中執行(導致SELECT * FROM Posts
):
.GroupBy(...)
.Select(x => new
{
x.TopicId,
Post = x.Posts.Where(z => z.CreatedDate == x.CreatedDate)
//Post = x.Posts.FirstOrDefault(z => z.CreatedDate == x.CreatedDate)
})
嘗試加入會給出 NotSupportedException(無法解析表達式):
.GroupBy(...)
.Join(_context.Posts,
(x, y) => x.TopicId == y.TopicId && x.CreatedDate == y.CreatedDate,
(x, post) => new
{
post.Title,
post.CreatedDate,
})
我知道我可以使用 SELECT N+1 來做到這一點(每個主題運行一個單獨的查詢),但我想避免這種情況。
基本上我現在正在做的是跑步后
var topics = _context.Posts.GroupBy(x => x.TopicId, (x, y) => new
{
CreatedDate = y.Max(z => z.CreatedDate),
TopicId = x,
}).ToList();
我構建以下查詢:
Expression<Func<Post, bool>> lastPostsQuery = post => false;
foreach (var topic in topics)
{
lastPostsQuery = lastPostsQuery.Or(post => post.TopicId == topic.TopicId && post.CreatedDate = topic.CreatedDate); //.Or is implemented in PredicateBuilder
}
var lastPosts = _context.Posts.Where(lastPostsQuery).ToList();
這會導致一個查詢(而不是 N),如SELECT * FROM Posts WHERE (Posts.TopicId == 1 AND Posts.CreatedDate = '2017-08-01') OR (Posts.TopicId == 2 AND Posts.CreatedDate = '2017-08-02') OR ...
.
效率不是很高,但由於每頁的主題數量很少,因此可以解決問題。
我不知道從哪個版本的 EFCore 開始是可能的,但現在有一個更簡單的單查詢替代方案:
context.Topic
.SelectMany(topic => topic.Posts.OrderByDescending(z => z.CreatedDate).Take(1),
(topic, post) => new {topic.Id, topic.Title, post.Text, post.CreatedDate})
.OrderByDescending(x => x.CreatedDate)
.ToList();
在 EF Core 2.1 GroupBy LINQ 運算符中,大多數情況下僅支持轉換為 SQL GROUP BY 子句。 聚合函數,如 sum、max ...
您可以在 EF Core 中使用Dapper 的完整支持組
我不確定 EFCore 的版本是否可行,但您可以嘗試以下操作:它將首先分組 select 最大 ID 並從每個組返回最大 ID 記錄。
var firstProducts = Context.Posts
.GroupBy(p => p.TopicId)
.Select(g => g.OrderByDescending(p => p.id).FirstOrDefault())
.ToList();
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.