首页 > 解决方案 > 按列分组并使用 Linq 获取组的第一条记录

问题描述

我正在尝试使用 Linq 查询数据库,以便仅从 SmsMessages 表中获取患者从每个患者发送的最后一条消息。我正在尝试按患者 ID 对消息进行分组,按日期对分组进行排序,然后返回该组的第一条记录,如下所示:

   var sms = await _dataContext.SmsMessages
                .GroupBy(message => message.PatientId)
                .Select(group => group.OrderByDescending(message => message.CreatedOn).FirstOrDefault())
                .ToListAsync();

类似问题的几个答案,例如,建议对上述内容进行变体,但在执行查询时收到以下错误:错误:

失败:Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware 1 执行请求时发生未处理的异常。System.InvalidOperationException:LINQ 表达式'(GroupByShaperExpression:KeySelector:(s.PatientId),ElementSelector:(EntityShaperExpression:EntityType:SmsMessage ValueBufferExpression:(ProjectionBindingExpression:EmptyProjectionMember)IsNullable:False)).OrderByDescending(message => message.CreatedOn)'无法翻译。要么以可翻译的形式重写查询,要么切换到客户评估。

标签: c#entity-frameworklinqasp.net-core

解决方案


在我的情况下,我无法在客户端进行分组,因为数据太重而无法在只需要最后一行时将所有行下载到客户端。在花了一些时间尝试不同的 ef core 和 LINQ 表达式之后,我发现的唯一方法是使用使用临时表的 Raw SQL 查询。SQL 查询如下所示:

SELECT message.* FROM message JOIN 
(SELECT PatientId, MAX(message.CreatedOn) AS CreatedOn 
FROM message GROUP BY message.PatientId) temp 
ON (message.PatientId = temp.PatientId and message.CreatedOn = temp.CreatedOn);

然后FromSqlRaw应该使用该方法使用实体框架调用此查询。

var sms = _dataContext.SmsMessages.FromSqlRaw(
    "SELECT message.* FROM message JOIN (SELECT PatientId, MAX(message.CreatedOn) AS CreatedOn FROM message GROUP BY message.PatientId) temp ON (message.PatientId = temp.PatientId and message.CreatedOn = temp.CreatedOn);").
    ToList();

推荐阅读