如何在EF Core中过滤单个孩子

时间:2019-07-18 20:00:17

标签: ef-core-2.0 ef-core-2.1

我正在使用EF Core 2.2.4

我有一个父表WorkOrders和子表WorkOrderResponses,我有以下查询来选择WorkOrders,然后仅选择其WorkOrderResponses的那些子IsFinalResponse标志为真

var workItemID = 1018 // this is parent id for WorkOrder
var result = await _dbContext.WorkOrders
                .Where(x => x.WorkOrderStatusID == 2 && x.WorkItemID == workItemID)
                .Select(x => new
                {
                    x.WorkOrderID,
                    x.WorkOrderStatusID,

                    // filter children
                    FinalResponse = x.WorkOrderResponses
                                    .Where(r => r.IsFinalResponse)
                                    .Select(r => r.Response)
                                    .ToList(),
                })
                .ToListAsync();

它返回正确的结果,包括已过滤的子级。在SQL事件探查器中,它仅按预期生成2个SQL查询

查询1

exec sp_executesql N'SELECT [x].[WorkOrderID], [x].[WorkOrderStatusID]
FROM [WorkOrders] AS [x]
WHERE ([x].[WorkOrderStatusID] = 2) AND ([x].[WorkItemID] = @__workItemID_0)
ORDER BY [x].[WorkOrderID]',N'@__workItemID_0 int',@__workItemID_0=1018

查询2

exec sp_executesql N'SELECT [t].[WorkOrderID], [x.WorkOrderResponses].[Response], [x.WorkOrderResponses].[WorkOrderID]
FROM [WorkOrderResponses] AS [x.WorkOrderResponses]
INNER JOIN (
    SELECT [x0].[WorkOrderID]
    FROM [WorkOrders] AS [x0]
    WHERE ([x0].[WorkOrderStatusID] = 2) AND ([x0].[WorkItemID] = @__workItemID_0)
) AS [t] ON [x.WorkOrderResponses].[WorkOrderID] = [t].[WorkOrderID]
WHERE [x.WorkOrderResponses].[IsFinalResponse] = 1
ORDER BY [t].[WorkOrderID]',N'@__workItemID_0 int',@__workItemID_0=1018

当我使用WorkOrderResponses过滤子项.Where(r => r.IsFinalResponse)时,我知道它将始终返回单个子项。因此,我将查询更改为使用SingeOrDefault而不是ToList()

var result = await _dbContext.WorkOrders
                    .Where(x => x.WorkOrderStatusID == 2 && x.WorkItemID == workItemID)
                    .Select(x => new
                    {
                        x.WorkOrderID,
                        x.WorkOrderStatusID,

                        // filter children
                        FinalResponse = x.WorkOrderResponses
                                        .Where(r => r.IsFinalResponse)
                                        .Select(r => r.Response)
                                        .SingleOrDefault(),
                    })
                    .ToListAsync();

但是,现在,如果运行sql profiler,它将为每个工作单创建sql。例如

exec sp_executesql N'SELECT TOP(2) [r0].[Response]
FROM [WorkOrderResponses] AS [r0]
WHERE ([r0].[IsFinalResponse] = 1) AND (@_outer_WorkOrderID = [r0].[WorkOrderID])',N'@_outer_WorkOrderID int',@_outer_WorkOrderID=2330

因此,对于给定的WorkItemID,我有1000个工作订单,那么将为每个工作订单生成1000次以上查询

如何选择“单身”或“第一个被过滤的孩子”?

0 个答案:

没有答案