有没有办法按多个列进行分组,就像使用 Linq 在 C# 中将这些列联合起来一样?
假设我有一个对象,它表示从一个用户发送到另一个用户的消息:
public class Message
{
public Int32 SenderId { get; set; }
public Int32 RecipientId { get; set; }
public String Text { get; set; }
public DateTime SentAt { get; set; }
}
我从存储库中获取了一组这些内容,然后我必须按发送日期对它们进行排序,并按SenderId、RecipientId
对进行过滤。但我只想从两个用户之间的给定对话中返回最后一条消息。方向并不重要,所以
(SenderId == 1 && RecipientId == 2)
应该被视为
(SenderId == 2 && RecipientId == 1)
到目前为止我得到了这个:
Messages
.GroupBy(m => new { m.SenderId, m.RecipientId })
.Select(gm => gm.OrderByDescending(m => m.SentAt).FirstOrDefault());
但这种方法的问题是,当我有一条消息从用户 1 发送到用户 2 时,反之亦然 2 => 1,两者都会被返回。因为键 (1,2) 与 (2,1) 不同。
任何建议都会很棒。谢谢!
UPD:我应该补充一点,我正在将表达式与 IQueryable 表达式一起使用。所以它是 LINQ to Entity。
最佳答案
即使您将问题标记为 entity-framework ,似乎并不是每个人都明白许多内存解决方案之所以失败是因为它们没有等效的 SQL。下面的查询将转换为 SQL,以供许多不同的 IQueryable
实现和查询提供程序使用:
Messages
.GroupBy(m => new
{
MinId = m.SenderId <= m.RecipientId ? m.SenderId : m.RecipientId,
MaxId = m.SenderId > m.RecipientId ? m.SenderId : m.RecipientId
})
.Select(gm => gm.OrderByDescending(m => m.SentAt).FirstOrDefault());
使用 Math.Min
/Math.Max
仅适用于 Entity Framework core 2,因为这是唯一自动切换到客户端评估的 EF 版本对于查询中不转换为 SQL 的任何部分。这在 EF core 3 中被放弃。EF core 3 仅在必要时在最终投影 (Select
) 中应用客户端评估。因此 GroupBy
在 EF core 3 中将会失败,而您迟早会使用它。
但是,我必须警告您,目前,这在 EF core 3 中不起作用,因为它们尚未完全支持 GroupBy
。但我确信这只是时间问题。
关于c# - 按多列分组,就好像它是一列一样,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59128314/