EFCore分组查询Group使用
关于EF中使用Group分组然后查询出第一个元素,对于新手,第一时间会想到如下的写法
C# 全选
var query = entityContext.sys_data.AsNoTracking();
var latestLogs = query.GroupBy(x => x.UserId)
.Select(g => g.OrderByDescending(x => x.DateAdded).First());
经过测试这样写是不行的, 运行后抛出System.InvalidOperationException
目前EF对Group的支持还停留在基本的聚合函数上, 详细的可以看EF仓库的这个Issue: Support ability to select top N of each group.
那么在EF提供对上面的那种写法的支持前, 我们就只能写原生sql来实现这个需求了吗? 其实不然, 我找到了一种替代的写法如下:
C# 全选
var query = entityContext.sys_data.AsNoTracking();
var latestLogs = query.Select(x => x.UserId)
.Distinct()
.SelectMany(x => query.Where(y => y.UserId == x).OrderByDescending(x => x.DateAdded).Take(1));
这种写法,生成的SQL语句如下:
SQL 全选
SELECT [t1].[Id], [t1].[ClientId], [t1].[DateAdded], [t1].[LoginResult], [t1].[UserId]
FROM (
SELECT DISTINCT [l].[UserId]
FROM [sys_data] AS [l]
) AS [t]
INNER JOIN (
SELECT [t0].[Id], [t0].[ClientId], [t0].[DateAdded], [t0].[LoginResult], [t0].[UserId]
FROM (
SELECT [l0].[Id], [l0].[ClientId], [l0].[DateAdded], [l0].[LoginResult], [l0].[UserId], ROW_NUMBER() OVER(PARTITION BY [l0].[UserId] ORDER BY [l0].[DateAdded] DESC) AS [row]
FROM [sys_data] AS [l0]
) AS [t0]
WHERE [t0].[row] <= 1
) AS [t1] ON [t].[UserId] = [t1].[UserId]
EF6中其实是支持直接GroupBy然后排序后的第一个元素的, EFCore这方面的支持居然迟迟不到位, 相关Issue在18年就有了, 无奈之下只能暂时曲线救国. 因为好几次遇到这种查询需求了, 所以这里记录一下, 希望EFCore快点提供相关功能的支持吧😓
版权声明:本文为YES开发框架网发布内容,转载请附上原文出处连接
post 张国生