2013-04-29 33 views
22

我有這樣一個表(表名:帖子):實體框架選擇每組的一個日期

+----+--------------------------+-------+------------+ 
| id |   content   | type | date | 
+----+--------------------------+-------+------------+ 
| 0 | Some text    | TypeA | 2013-04-01 | 
| 1 | Some older text   | TypeA | 2012-03-01 | 
| 2 | Some even older texttext | TypeA | 2011-01-01 | 
| 3 | A dog     | TypeB | 2013-04-01 | 
| 4 | And older dog   | TypeB | 2012-03-01 | 
| 5 | An even older dog  | TypeB | 2011-01-01 | 
+----+--------------------------+-------+------------+ 

使用LINQ表達我想找到每種類型的最新內容,所以結果應該是

Some text | TypeA 
A dog  | TypeB 

我已經嘗試了幾件事情,但沒有指出非工作表達式。

回答

50

如果你想獲得整個帖子。你可以試試這個:

var query = Posts.GroupBy(p => p.Type) 
        .Select(g => g.OrderByDescending(p => p.Date) 
           .FirstOrDefault() 
        ) 
+0

組運行查詢之前或之後運行?那麼它會從數據庫中拉出每一行,然後對它們進行分組,或者是否將查詢語句添加到查詢中,以便僅拉取分組行? – Samir 2017-12-27 11:21:36

+0

@Samir:這確實是一個很好的觀點。根據EF上的版本,它似乎有不同的行爲。 EF 7似乎將數據加載到客戶端並進行分組:https://stackoverflow.com/questions/11564311/sql-to-entity-framework-count-group-by。 EF核心似乎有支持sql組:https://github.com/aspnet/EntityFrameworkCore/pull/9872。爲了確認這一點,你可以使用一個分析器來查看實際的sql查詢。 – 2017-12-30 02:31:58

+0

@Samir:如果您使用的是EF Core最新版本且性能可以接受,即使sql查詢不使用group by(將函數中的代碼包裝進來,以便稍後需要重構),也可以考慮使用此解決方案,似乎人們已經考慮到了這一點,後來的版本可能會支持這一點。否則,你必須編寫原始的sql查詢。 – 2017-12-30 02:36:08

2

我想你可以將你的帖子類型行,然後由該類型

from row in Posts 
group row by row.type 
into g 
select new 
{  
    Content = (from row2 in g orderby row2.date descending select row2.content).FirstOrDefault(), 
    Type = g.Key 
} 
+0

這似乎是工作(後添加「」和第一變爲FirstOrDefault()是否有辦法讓整個帖子,或者我需要構建它的。 「select new」? – Todilo 2013-04-29 08:12:14

+1

@Todilo我無法測試它沒有模型,所以對於錯誤感到抱歉:)您可以通過將row2.content的返回結果更改爲row2來獲得Post,但無論如何group by是無論如何因爲您需要最新的「每種類型」的內容。你也可以嘗試獲取不同的類型,然後按類型選擇頂部1 Post按日期排序,我想這個查詢會更有效 – Alex 2013-04-29 08:39:52

+0

我明白了。我會用「手動」方式再次創建模型,這似乎是最有效的方法。非常感謝你! – Todilo 2013-04-29 08:47:13

1

或最新集合降支下令使用臨時結果選擇第一內容和謂語

var tmp = posts.GroupBy(x => x.type).Select(x => new {x.Key, date = x.Max(g => g.date)).ToArray(); 

var filter = PredicateBuilder.False<Post>(); 

foreach (var item in tmp) 
{ 
    filter = filter.Or(x => x.type == item.Key && x.date == item.date); 
} 

var newestPosts = posts.Where(filter); 
+0

由於上面的例子沒有工作,我還沒有測試過。以前沒有見過PredicateBuilder,但似乎是我應該學習的一個很酷的功能。謝謝。 – Todilo 2013-04-29 08:26:43

0

從內存,像這樣的事情應該這樣做

var data = context.Posts.Group(p => p.Type) 
         .Select(g => new { 
              Type = g.Key, 
              Date = g.OrderByDescending(p => p.Date) 
                .FirstOrDefault() 
             } 

這將gi給你一個新的匿名類型,但你可以隨時將它映射到一個類

+0

您的意思是GroupBy(...) – 2016-05-25 09:07:52