Entity framework core LINQ-实体框架核心-仅当最新记录与另一个条件匹配时才选择该记录

Entity framework core LINQ-实体框架核心-仅当最新记录与另一个条件匹配时才选择该记录,entity-framework-core,linq-to-entities,Entity Framework Core,Linq To Entities,我有一个看起来像这样的数据集。我想选择节点的最新记录状态为“挂起”的所有行 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

我有一个看起来像这样的数据集。我想选择节点的最新记录状态为“挂起”的所有行

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
仅当最新记录的状态为“挂起”(否则,不要为该节点选择任何内容)时,才应返回每个节点的记录。因此,对于上面的数据集,查询将只返回以下内容:

2       Pending    Other         2020-03-13 03:35:00.00000+00

我想使用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核心中实现
GroupBy
。在如何与
i分组
结果交互方面,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();
这看起来真的很糟糕,但是快速浏览一下:
我们首先根据节点ID对节点进行分组,然后根据分组结果使用Max选择最新的时间戳以获得最大的时间戳,并且还使用分组键选择节点ID。这为我们提供了
{Timestamp(max row),NodeId}
的结构。使用此方法,我们
连接回节点集,使用节点ID和时间戳的键比较将所选结果与节点集合配对,以便将这些分组项转换回节点实体。这将向我们返回与节点ID和最大时间戳匹配的节点集合,即“最新节点”。在此基础上,我们应用
Where
子句仅选择处于“挂起”状态的最新节点

如果您希望最新的节点记录具有挂起状态,并假设您可以有一个节点多次切换到“挂起”:即

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核心中实现
GroupBy
。在如何与
i分组
结果交互方面,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();
这看起来真的很糟糕,但是快速浏览一下:
我们首先根据节点ID对节点进行分组,然后根据分组结果使用Max选择最新的时间戳以获得最大的时间戳,并且还使用分组键选择节点ID。这为我们提供了
{Timestamp(max row),NodeId}
的结构。使用此方法,我们
连接回节点集,使用节点ID和时间戳的键比较将所选结果与节点集合配对,以便将这些分组项转换回节点实体。这将向我们返回与节点ID和最大时间戳匹配的节点集合,即“最新节点”。在此基础上,我们应用
Where
子句仅选择处于“挂起”状态的最新节点

我是这样做到的:

var pending = myContext.Records
                         .GroupBy(t => t.Nodeid)
                         .Select(grp => grp.OrderByDescending(t => t.Utctimestamp).First())
                         .Where(t => t.Status == "Pending");

我是这样做到的:

var pending = myContext.Records
                         .GroupBy(t => t.Nodeid)
                         .Select(grp => grp.OrderByDescending(t => t.Utctimestamp).First())
                         .Where(t => t.Status == "Pending");

谢谢@Steve Py,但是如果最近的记录状态为“挂起”(而不是最近出现的“挂起”状态),我只想返回节点的最新记录。因此,如果最近的记录没有“挂起”状态,则不应返回任何内容。我对OP做了一个小的编辑,让它更清晰一些。我也在使用EF Core。好吧,这是一个尝试,它听起来像你在寻找什么。感谢您澄清您正在使用EF Core。(对情况没有帮助:)不过,我想我有一个解决方案,可以满足你的需求。我用EF核心更新更新了答案,以获取最新状态为挂起的项目。太难看了。谢谢@Steve Py。我设法找到了一个相当优雅的解决方案,我将其作为答案发布。谢谢@Steve Py,但是我只想在最近的记录状态为“挂起”(而不是最近出现的“挂起”状态)时返回节点的最新记录。因此,如果最近的记录没有“挂起”状态,则不应返回任何内容。我对OP做了一个小的编辑,让它更清晰一些。我也在使用EF Core。好吧,这是一个尝试,它听起来像你在寻找什么。感谢您澄清您正在使用EF Core。(对情况没有帮助:)然而,我想我有一个解决办法,可以给你什么