EF/Linq - 对集合进行分组前进行排序

5
我有一个项目表和一个审计表之间的一对多关系。我试图从审计表中挑选出每个项目实体的最新条目。
据我所知,要做到这一点,我应该能够按日期对我的审计集合进行排序,然后按项目ID进行分组,以便我可以选择每个组(项目ID)的第一条目录以获取最新的条目。
但是当我运行我的ef/linq查询时,结果不正确,而且似乎忽略了order-by - 即使生成的sql也不包括order by语句。
这是我尝试过的简单示例。
using (var ctx = new MyDbContext())
{
    var audit = from a in ctx.ProjectAudits
                orderby a.CreatedDate descending
                group a by a.ProjectId into grp
                select grp.FirstOrDefault();

    var resultsList = audit.ToList();
}

查询结果总是返回每个项目ID的最早审核条目,而不是最新的。

这个查询有什么问题吗?我是否漏掉了一些明显的东西?


排序会影响结果,而不是您加入的表。 - Jodrell
@Jodrell 好的,那么我如何确保当我获取每个组的第一个条目时,第一个条目是最新的? - Chris Moutray
在T-SQL中,你不能真正地用一条语句来实现这个 - 按项目ID分组将为每个项目ID提供单行,并聚合其他列的值 - 你需要使用子查询来获取每个项目的第一个项,不确定如何将其转换为EF或Linq... - Charleh
@Charleh 这就是我面临的问题 - 我可以使用子查询编写 SQL(实际上没有使用 group by),但将 ef 翻译成不起作用的部分对我来说很困难 - 我找到了这个答案 https://dev59.com/0VHTa4cB1Zd3GeqPQ2L9#4014958,它最初执行 group by,然后使用它来驱动另一个查询,即选择实体和其中一个连接实体 - 我采用了这种方法并添加了 order by,但它不起作用... - Chris Moutray
2个回答

6

更新

好的,那这样怎么样?

ctx.ProjectAudits
    .GroupBy(p => p.ProjectId)
    .Select(p => p.OrderByDescending(j => j.CreatedDate).FirstOrDefault())
    .ToList();

我这里没有VS,但是理论上它应该能把你的记录进行分组,按照它们的创建日期对它们进行排序,并选择每个组中的第一条记录。


每个项目实体的最新条目。您的查询仅选择一个项目的条目。 - HoberMellow
@HoberMellow,对于所有项目,我想列出最新的审计实体,而不仅仅是一个项目。 - Chris Moutray
@Trickery 做得好!这个方法很管用,仔细看过之后很有道理 :) - Chris Moutray

1

我认为你需要考虑一个不同的方法。不要按顺序排序,而是分组并选择具有最大 CreatedDate 的审计。以下内容未经测试,仅供参考:

var audit = from a in ctx.ProjectAudits
            group a by a.ProjectId into grp
            select new {
              // whatever your other properties are
              CreatedDate = grp.Max(i => i.CreatedDate)
            };

或者,大多数人更喜欢使用方法语法:


var audit = ctx.ProjectAudits
               .Where(i => i.CreatedDate == ctx.ProjectAudits
                                               .Max(x => x.CreatedDate));

编辑 - 做了一些更改,并使用测试类和List<TestClass>进行了测试,以上内容适用于该测试。


@HoberMellow 是的,没错,不错。 - Paul Aldred-Bann

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接