我有一个看起来像这样的数据集。我想选择节点最近记录的状态为“待处理”的所有行]
Nodeid Status Type Utctimestamp
------ ----- ------ --------
1 Pending Transaction 2020-03-13 03:31:00.00000+00
1 Overridden Transaction 2020-03-13 03:32:00.00000+00
2 Unknown Other 2020-03-13 03:34:00.00000+00
2 Pending Other 2020-03-13 03:35:00.00000+00
仅当最新记录的状态为Pending
时,才应返回每个节点的记录(否则,不要为该节点选择任何内容)。因此,对于上面的数据集,查询将仅返回以下内容:
2 Pending Other 2020-03-13 03:35:00.00000+00
我想使用流利的语法(“方法语法”)在Entity Framework中使用LINQ查询。我该怎么办?
node ID Status Time
1 Pending xxxx
1 Submitted xxxy
1 Pending xxxz
您想在时间行“ xxxz”的地方:
使用EF6
string pendingStatus = Status.Pending.ToString();
var pending = myContext.TransactionMsg
.Where(x => x.Status == pendingStatus)
.GroupBy(x => x.NodeId)
.Select(g => g.OrderByDescending(x => x.UtcTimestamp).FirstOrDefault())
.ToList();
现在我无法在EF Core上使用它(惊喜,令人惊讶),因此,如果您在使用Core,则需要进行一些挖掘,以找出如何解决它似乎无法解决的问题。从组表达式中选择OrderByDescending
。坚持使用EF 6的另一个理由:)
更新:好的,基于仅获取最新状态为待决节点的要求。通过将Where
子句移到Select
之后,在EF6中获得此相对简单。
在EF Core中执行此操作要困难得多,但看起来确实可行。最大的问题是如何在EF Core中实现GroupBy
。关于如何与IGrouping
结果进行交互的更多限制,其中EF6可以成功地将它们作为一组进行平移/交互,而EF Core将尝试将OrderBy和此类表达式与分组结果一起使用的情况除外。因此,您需要更加详细:
var results = context.Nodes
.GroupBy(x => x.NodeId, (x,y) => new { Timestamp = y.Max(z => z.Timestamp), NodeId = x })
.Join(context.Nodes, a => new { a.NodeId, a.Timestamp }, b => new { b.NodeId, b.Timestamp }, (a,b) => b)
.Where(g => g.Status == "Pending")
.ToList();
这看上去确实很烂,但是快速浏览一下:我们首先按Node ID对节点进行分组,然后从中选择Max(相对于分组结果)使用最新的Timestamp,以获得最大的Timestamp,然后使用分组的Key选择Node ID。这给出了{ Timestamp (max row), NodeId }
的结构。使用此,我们Join
返回到Nodes集合,使用Node ID和Timestamp的键比较将我们选择的结果与Nodes集合配对,以便我们可以将这些分组的项目转换回Node实体。这将返回与节点ID和最大时间戳匹配的节点集合,即“最新节点”。从中,我们应用Where
子句仅选择处于“待处理”状态的最新节点。