简体   繁体   English

使用 Linq 按列分组并获取组的第一条记录

[英]Group by column and get first record of group using Linq

I'm trying to query a database using Linq to get only the last message a patient has sent from every patient from the SmsMessages table.我正在尝试使用 Linq 查询数据库,以便仅从 SmsMessages 表中获取患者从每个患者发送的最后一条消息。 I am trying to group the messages by patient Id, sort the groupings by the date, and then return the first record of that group, like follows:我正在尝试按患者 ID 对消息进行分组,按日期对分组进行排序,然后返回该组的第一条记录,如下所示:

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

Several answers to similar questions, for example , suggest doing a variation of the above, but I receive the following error when the query executes: The error:类似问题的几个答案, 例如,建议对上述内容进行变体,但在执行查询时收到以下错误:错误:

fail: Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware 1 An unhandled exception has occurred while executing the request.失败:Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware 1执行请求时发生未处理的异常。 System.InvalidOperationException: The LINQ expression '(GroupByShaperExpression: KeySelector: (s.PatientId), ElementSelector:(EntityShaperExpression: EntityType: SmsMessage ValueBufferExpression: (ProjectionBindingExpression: EmptyProjectionMember) IsNullable: False ) ).OrderByDescending(message => message.CreatedOn)' could not be translated. System.InvalidOperationException:LINQ 表达式'(GroupByShaperExpression:KeySelector:(s.PatientId),ElementSelector:(EntityShaperExpression:EntityType:SmsMessage ValueBufferExpression:(ProjectionBindingExpression:EmptyProjectionMember)IsNullable:False)>).OrderByDescending'(message无法翻译。 Either rewrite the query in a form that can be translated, or switch to client evaluation.要么以可翻译的形式重写查询,要么切换到客户评估。

In my case I couldn't afford grouping on client side since the data was too heavy to download all the rows into client side when only the last row was needed.在我的情况下,我无法在客户端进行分组,因为数据太重而无法在只需要最后一行时将所有行下载到客户端。 After spending some time trying different ef core and LINQ expressions, the only way I found was using Raw SQL query which uses a temp table.在花了一些时间尝试不同的 ef core 和 LINQ 表达式之后,我发现的唯一方法是使用使用临时表的 Raw SQL 查询。 The SQL query looks like: 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);

Then the method FromSqlRaw should be used to call this query using entity framework.然后应该使用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();

This issue is related to Client vs. Server Evaluation .此问题与Client vs. Server Evaluation相关。

Before performing GroupBy, you need to add ToList() operation to _dataContext.SmsMessages to convert the server-side operation to the client side.在执行 GroupBy 之前,需要在_dataContext.SmsMessages中添加ToList()操作,将服务端操作转换为客户端。

Otherwise, on the server side, sql server cannot recognize client-side methods .否则,在服务器端, sql 服务器无法识别客户端方法

Just change your code as follow:只需将您的代码更改如下:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM