如何在 EF Core 中按条件获取最新条目?
Posted
技术标签:
【中文标题】如何在 EF Core 中按条件获取最新条目?【英文标题】:How do I get the most recent entry by condition in EF Core? 【发布时间】:2021-11-16 13:57:52 【问题描述】:我有一个具有以下结构(和示例数据)的表:
Identifier | UseDate | PartId |
---|---|---|
a123 | 05/01/2000 | 237 |
a123 | 05/01/2000 | 4656 |
a123 | 01/01/2000 | 2134 |
a124 | 04/01/2000 | 5234 |
a124 | 01/01/2000 | 2890 |
我需要获取每个(非唯一)标识符的最新条目,但每个标识符最多一个。
似乎可以解决我的问题的 SQL 查询(MariaDB)如下:
SELECT a.Identifier, a.MaxDate, b.PartId, b.UseDate
FROM
(SELECT Identifier, MAX(UseDate) AS MaxDate FROM MyTable GROUP BY Identifier) a
LEFT JOIN MyTable b ON a.Identifier = b.Identifier
WHERE a.MaxDate = b.UseDate GROUP BY a.Identifier;
但是我需要它来使用 C# 和 EF Core (Pomelo.EntitiFrameworkCore.mysql 5.0.3),我的尝试是:
var q1 = db.MyTable
.GroupBy(t => t.Identifier)
.Select(t => new Identifier = t.Key, MaxDate = t.Max(x => x.UseDate) );
return new ObjectResult(db.MyTable
.Join(
q1,
t1 => t1.Identifier,
t2 => t2.Identifier,
(t1, t2) => new Identifier = t2.Identifier, PartId = t1.PartId, MaxDate = t1.MaxDate, UseDate = t1.UseDate )
.Where(t => t.UseDate == q1.First(x => x.Identifier == t.Identifier).MaxDate)
.GroupBy(t => t.Identifier)
.ToList()
);
和
return new ObjectResult(db.MyTable
.GroupBy(t => t.Identifier)
.Select(t => t.OrderByDescending(x => x.UseDate).FirstOrDefault())
.ToList()
);
第一个抛出这个错误:
System.InvalidOperationException:“无法翻译给定的 'GroupBy' 模式。在 'GroupBy' 之前调用 'AsEnumerable' 以在客户端对其进行评估。”
第二个基本上产生相同的结果,只是抱怨 LINQ 表达式而不是 GroupBy。
我想避免使用原始 SQL,但如何正确(并希望有效地)实现它?
【问题讨论】:
您的目标是哪个 EFC 版本? 我正在使用 Pomelo.EntityFrameworkCore.MySql 5.0.3。 【参考方案1】:在 LINQ 中编写此类查询的方法有很多,其中大多数都可以通过 EF Core 5/6+ 进行翻译。
为必要的分组和聚合定义子查询后,直接的方法是将其加入数据表,但不能使用 join
运算符 - 而是使用行限制相关子查询(SelectMany
和 Where
和Take
),例如
var query = db.MyTable
.GroupBy(t => t.Identifier)
.Select(t => new Identifier = t.Key, MaxDate = t.Max(x => x.UseDate) )
.SelectMany(g => db.MyTable
.Where(t => t.Identifier == g.Identifier && t.UseDate == g.MaxDate)
.Take(1));
如果排序字段对于每个其他键值都是唯一的(即在您的情况下,如果 UseDate
对于每个唯一的 Identifier
值都是唯一的),您可以直接使用 Join
运算符(因为需要限制),例如
var query = db.MyTable
.GroupBy(t => t.Identifier)
.Select(t => new Identifier = t.Key, MaxDate = t.Max(x => x.UseDate) );
.Join(db.MyTable,
g => new g.Identifier, UseDate = g.MaxDate ,
t => new t.Identifier, t.UseDate ,
(g, t) => t);
或直接将Max
基于Where
条件应用于数据表:
var query = db.MyTable
.Where(t => t.UseDate == db.MyTable
.Where(t2 => t2.Identifier == t.Identifier)
.Max(t2 => t2.UseDate)
);
最后,获得每组前 1 项的“标准”LINQ 方式。
对于 EF Core 6.0+:
var query = db.MyTable
.GroupBy(t => t.Identifier)
.Select(g => g
.OrderByDescending(t => t.UseDate)
.First());
对于 EF Core 5.0,必须模拟查询内的分组结果集:
var query = db.MyTable
.GroupBy(t => t.Identifier)
.Select(g => db.MyTable
.Where(t => t.Identifier == g.Key)
.OrderByDescending(t => t.UseDate)
.First());
【讨论】:
以上是关于如何在 EF Core 中按条件获取最新条目?的主要内容,如果未能解决你的问题,请参考以下文章
如何在 EF / EF Core 中的第二个表上实现具有某些条件的左连接?
如何在 .net core ef 上应用 thenInclude 条件?
如何在 C# EF Core 中使用 join 子句中的条件编写 SQL 命令