c#-根据最近相关实体的值选择实体集合

在我当前的项目中,我经常在几个地方遇到相同类型的困难.

最简单的实例如下:

我有两个相关的实体,Request和RequestAction.
每个RequestAction都有一个状态和一个时间戳,并指向一个Request.

我需要根据最近相关的RequestAction的状态查询请求的集合.

示例:获取所有最近RequestAction状态为“ Open”的请求.

对数据库进行非规范化以使最新状态成为Request实体的属性不是一种选择.

在我的应用程序的许多其他地方,我需要相同类型的过滤.我会跟踪许多版本的项目以进行历史记录和审核,但是我通常只想查看每个项目的最新版本.

我可以想到两种解决方案,但都不是特别有吸引力.

1)我可以手动编写SQL.对于此问题的原始SQL答案包括:在表的一个实例的时间戳大于另一个实例的时间戳的情况下,通过外部联接将表与其自身连接,然后在第二个表为null的位置查找记录,表明没有更大的时间戳可以被发现.这就是我过去处理场景的方式.由于它使用索引,因此在数据库中非常有效,这与其中带有最大值的子查询不同.但是,强烈建议我的开发团队使用实体与数据库进行对话,因此强烈建议不要使用此解决方案.

2)我可以使用实体将所有值加载到内存中,并在我的代码中手动循环查找要查找的值.代码看起来像这样:

var openRequests = new List<Request>();
var allRequests = context.Requests;
foreach (var request in allRequests)
{
    var recentAction = request.RequestActions
        .OrderByDescending(c => c.ActionTimestamp)
        .First();
    if (recentAction.Status == "Open")
    {
        openRequests.Add(request);
    }
}

虽然这可以为我提供所需的结果,但效率极低,并且浪费大量资源和执行时间.我要查询的数据库很大,并且遍历每条记录确实是不可行的.

是否有使用实体执行此操作的有效方法?我很难想象我是唯一需要这种功能的人.

解决方法:

您可以在单个数据库查询中使用LINQ to Entities查询此:

var openRequests = context.Requests
    .Where(r => r.RequestActions
        .OrderByDescending(ra => ra.ActionTimestamp)
        .Select(ra => ra.Status)
        .FirstOrDefault() == "Open")
    .ToList();

生成的SQL如下所示:

SELECT 
[Extent1].[Id] AS [Id], 
[Extent1].[SomeProp1] AS [SomeProp1], 
[Extent1].[SomeProp2] AS [SomeProp2], -- ...etc.
FROM  [dbo].[Requests] AS [Extent1]
CROSS APPLY  (SELECT TOP (1) [Project1].[Status] AS [Status]
    FROM ( SELECT 
           [Extent2].[Status] AS [Status], 
           [Extent2].[ActionTimestamp] AS [ActionTimestamp]
           FROM [dbo].[RequestActions] AS [Extent2]
           WHERE [Extent1].[Id] = [Extent2].[RequestId]
    ) AS [Project1]
    ORDER BY [Project1].[ActionTimestamp] DESC ) AS [Limit1]
WHERE N'Open' = [Limit1].[Status]

我不知道这是否是一个“好”的高性能SQL.

上一篇:c#-与多个条件存在的Linq查询等效


下一篇:c#-如何获取表/视图名称(即删除架构前缀)