实体框架核心不选择子行数

时间:2018-03-16 20:47:30

标签: sql-server entity-framework-core

尝试检索子行数时,EF 6的行为正确:只有一个不错的SQL查询。另一方面,EF Core可以按子行计数进行排序,但不会在生成的SQL查询中选择它。它只是迭代每个结果并执行Count(*) SQL查询。

以下是我的模型类:

public class Parent
{
    [Key]
    public int Id { get; set; }
    public string Name { get; set; }
    public List<Child> Children { get; set; }
}

public class Child
{
    [Key]
    public int Id { get; set; }
    public string Name { get; set; }

    public int ParentId { get; set; }
    public Parent Parent { get; set; }
}

以下是查询(用于EF Core和EF 6):

var query = context.Parents
                   .Take(4)
                   .Select(p => new
                                 {
                                     Parent = p,
                                     ChildrenCount = p.Children.Count(),
                                 });

var results = query.OrderBy(x => x.ChildrenCount).ToList();

EF 6生成此SQL:

SELECT 
    [Project1].[Id] AS [Id], 
    [Project1].[Name] AS [Name], 
    [Project1].[C1] AS [C1]
FROM 
    (SELECT TOP (4) 
         [c].[Id] AS [Id], 
         [c].[Name] AS [Name], 
         (SELECT COUNT(1) AS [A1]
          FROM [dbo].[Children] AS [Extent2]
          WHERE [c].[Id] = [Extent2].[ParentId]) AS [C1]
     FROM [dbo].[Parents] AS [c])  AS [Project1]
ORDER BY [Project1].[C1] ASC

EF Core生成:

exec sp_executesql N'SELECT [t].[Id], [t].[Name]
FROM (
SELECT TOP(@__p_0) [p].[Id], [p].[Name]
FROM [Parents] AS [p]
) AS [t]
ORDER BY (
SELECT COUNT(*)
FROM [Children] AS [c]
WHERE [t].[Id] = [c].[ParentId]
)',N'@__p_0 int',@__p_0=4

exec sp_executesql N'SELECT COUNT(*)
FROM [Children] AS [c1]
WHERE @_outer_Id = [c1].[ParentId]',N'@_outer_Id int',@_outer_Id=3

exec sp_executesql N'SELECT COUNT(*)
FROM [Children] AS [c1]
WHERE @_outer_Id = [c1].[ParentId]',N'@_outer_Id int',@_outer_Id=1

exec sp_executesql N'SELECT COUNT(*)
FROM [Children] AS [c1]
WHERE @_outer_Id = [c1].[ParentId]',N'@_outer_Id int',@_outer_Id=2

如果我有1000行,它将生成1001个SQL查询。如何解决?

我正在使用最新版本的EF Core(2.0.2)和SQL Server。

1 个答案:

答案 0 :(得分:0)

我通过使用连接找到了一种解决方法:

            var query = context.Parents
                                .Join(context.Parents
                                .Select(p => new
                                {
                                    Id = p.Id,
                                    ChildrenCount = p.Children.Count(),
                                }),
                                l => l.Id,
                                r => r.Id,
                                (l, r) => new { l, r.ChildrenCount })
                                .OrderBy(x => x.l.Name)
                                .Take(4);

            var results = query.ToList();

生成单个查询:

exec sp_executesql N'SELECT TOP(@__p_0) [l].[Id], [l].[Name], [t].[Id], [t].[ChildrenCount]
FROM [Parents] AS [l]
INNER JOIN (
SELECT [p].[Id], (
    SELECT COUNT(*)
    FROM [Children] AS [c]
    WHERE [p].[Id] = [c].[ParentId]
) AS [ChildrenCount]
FROM [Parents] AS [p]
) AS [t] ON [l].[Id] = [t].[Id]
ORDER BY [l].[Name]',N'@__p_0 int',@__p_0=4

它的效率低于ef6,但至少它在一次查询中完成。