c# - 如何对记录进行分组并仅检索具有前 N 条记录的第一组

标签 c# entity-framework linq entity-framework-core ef-core-2.0

我有以下记录集

ID          BatchID     ClientName           CreatedDateTime
----------- -------------- --------------- -----------------------
1           NULL           B             2018-02-16 19:07:46.320
2           NULL           B             2018-02-16 19:07:46.320
3           NULL           B             2018-02-16 19:07:46.597
4           NULL           B             2018-02-16 19:07:46.597
5           NULL           B             2018-02-16 19:10:10.260
6           NULL           B             2018-02-16 19:10:10.260
7           NULL           B             2018-02-16 19:21:34.303
8           NULL           B             2018-02-16 19:21:34.303
9           NULL           B             2018-02-16 19:21:44.780
10          NULL           B             2018-02-16 19:21:44.780
11          NULL           A             2018-02-16 19:24:35.623
12          NULL           A             2018-02-16 19:24:35.623
13          NULL           A             2018-02-16 19:24:42.867
14          NULL           A             2018-02-16 19:24:42.867

我在 EF Core 中使用 LINQ to SQL。

我想过滤BatchIDNULL的记录,然后按CreatedDateTime对过滤后的记录进行排序,然后按分组ClientName,然后从第一个组中获取前 5 条记录。

根据上面给定的记录集,它应该为 ClientName B 返回 ID 为 1,2,3,4,5 的记录

这是我的问题

 var result = await _DBContext.BatchRequests
                .Where(x => x.BatchID.HasValue == false)
                .OrderBy(x => x.CreatedDateTime)
                .GroupBy(x => x.ClientName)
                .FirstAsync();

问题
1> 查询返回Client A
2> 我如何只取前 5 条记录

更新 1

Sql Profiler 显示如下,它甚至不在 SQL 中分组

SELECT [x].[ID], [x].[BatchID], [x].[ClientName], [x].[CreatedDateTime]
FROM [BatchRequests] AS [x]
WHERE CASE
    WHEN [x].[BatchID] IS NULL
    THEN CAST(1 AS BIT) ELSE CAST(0 AS BIT)
END <> 0
ORDER BY [x].[ClientName]

最佳答案

首先,如果在将 LINQ 查询转换为 SQL 的 Queryable 实现中紧跟 GroupBy,通常 OrderBy 没有效果(被忽略)。

其次,EF Core 目前不会将 GroupBy 查询转换为 SQL,而是在内存中处理它们(所谓的 client evaluation ),这使得它们非常低效。考虑到这一点,您最好将工作分成两个查询 - 一个获取第一组的 ClientName,第二个获取所需的结果:

var baseQuery = _DBContext.BatchRequests
    .Where(x => x.BatchId == null)
    .OrderBy(x => x.CreatedDateTime);

var clientName = await baseQuery
    .Select(x => x.ClientName)
    .FirstOrDefaultAsync();

var result = await baseQuery
    .Where(x => x.ClientName == clientName)
    .Take(5)
    .ToListAsync();

实际上你可以结合这两个查询,但我不确定它是否会更有效率(可能更糟):

var baseQuery = _DBContext.BatchRequests
    .Where(x => x.BatchId == null)
    .OrderBy(x => x.CreatedDateTime);

var result = await baseQuery
    .Where(x => x.ClientName == baseQuery.Select(y => y.ClientName).FirstOrDefault())
    .Take(5)
    .ToListAsync();

关于c# - 如何对记录进行分组并仅检索具有前 N 条记录的第一组,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48834396/

相关文章:

c# - 如何避免传递给构造函数的多个参数的赋值

c# - Nest 无法使用 EF6/MVC5 处理大型数据库模型

c# - 更新条目向数据库添加一个新条目

c# - 订购 XElements

c# - ToList() 方法在哪里? (可查询)

c# 将 winforms 图表绑定(bind)到对象列表

c# - 文件.复制后文件.删除

c# - 不支持 Linq to Entities SqlFunctions.DateDiff

c# - 在 LINQ to Entities 中重用选择表达式

c# - Entity Framework 加入说明