C# 然而,在进行了一些小的更改之后,可能会发现LINQtoSQL在分组方面效率很低。如果您的操作“错误”(见下文),它可能会执行一个分组查询,然后对每个组执行查询,以填充这些组

C# 然而,在进行了一些小的更改之后,可能会发现LINQtoSQL在分组方面效率很低。如果您的操作“错误”(见下文),它可能会执行一个分组查询,然后对每个组执行查询,以填充这些组,c#,linq,linq-to-sql,C#,Linq,Linq To Sql,这是因为在SQL中,GROUPBY是“破坏性的”:它不会从查询的表返回完整记录。如果你这样做 选择a,求和(b) 从表格 分组 您将得到一个由两个值组成的结果集,而不是表a中的其他值。但是,在LINQ中,您通常不仅对聚合感兴趣,而且可能只想按某些属性对完整实体进行分组,如下面的简单示例: 来自As中的 按a分组。输入g 选择新的{Type=g.Key,As=g} 这将首先按.Type执行分组查询,然后执行尽可能多的查询以获取每个组的实体。对于这些类型的分组,几乎总是最好先获取数据(一个查询)

这是因为在SQL中,GROUPBY是“破坏性的”:它不会从查询的表返回完整记录。如果你这样做

选择a,求和(b)
从表格
分组
您将得到一个由两个值组成的结果集,而不是
表a
中的其他值。但是,在LINQ中,您通常不仅对聚合感兴趣,而且可能只想按某些属性对完整实体进行分组,如下面的简单示例:

来自As中的
按a分组。输入g
选择新的{Type=g.Key,As=g}
这将首先按.Type执行
分组
查询,然后执行尽可能多的查询以获取每个组的实体。对于这些类型的分组,几乎总是最好先获取数据(一个查询),然后在内存中进行分组


(这是实体框架击败LINQ到SQL wrt查询生成的罕见领域之一)

如果您已经有了SQL,为什么要将其转换为LINQ。只需在db上下文中执行SQL语句。因为我想要一个纯linq解决方案,而不是任何SQL。这更相关,感谢对分组的深入了解,这很有意义。实际上,我没有注意到组键上的firstOrDefault()。看来linq这个东西要花的时间几乎和我学习SQL所花的时间一样多:S
var query1 = (
            from sl in slRepo
            where sl.Product.bsDepartmentId < 90 && sl.Product.SubDepartment.Department.Id == departmentId
            group sl by sl.Location into gbsl
            select new
            {
                ProductId = gbsl.FirstOrDefault().Product.Id,
                LocationId = gbsl.FirstOrDefault().Location.Id,
                Location = gbsl.FirstOrDefault().Location.Name,
                Quantity = gbsl.Sum(x => x.CurrentStock),
                LastInvoice = gbsl.Max(x => x.LastInvoice)
            });

var query2 = (
            from sd in sdRepo
            where sd.Product.SubDepartment.Department.Id == departmentId
            group sd by sd.Location.Id into g
            select new
            {
                LocationId = g.FirstOrDefault().Location.Id,
                LastSale = g.Max(x => x.TransactionDate)
            });

var query3 = (
            from q1 in query1
            join q2 in query2 on q1.LocationId equals q2.LocationId into temp
            from j in temp.DefaultIfEmpty()
            select new XStockOverviewDto
            {
                Location = q1.Location,
                Quantity = q1.Quantity,
                LastInvoice = q1.LastInvoice,
                LastSale = j.LastSale
            });

        return query3;
SELECT 
1 AS [C1], 
[Project10].[Name] AS [Name], 
[Project10].[C2] AS [C2], 
[Project10].[C3] AS [C3], 
 CAST( [Project16].[C2] AS datetime2) AS [C4]
FROM   (SELECT 
    [Project9].[Name] AS [Name], 
    [Project9].[C1] AS [C1], 
    [Project9].[C2] AS [C2], 
    (SELECT 
        MAX([Filter9].[LastInvoice]) AS [A1]
        FROM ( SELECT [Extent18].[LastInvoice] AS [LastInvoice], [Extent20].[Department_Id] AS [Department_Id], [Extent21].[Id] AS [Id1]
            FROM    [dbo].[XStockLevels] AS [Extent18]
            INNER JOIN [dbo].[XProducts] AS [Extent19] ON [Extent18].[Product_Id] = [Extent19].[Id]
            LEFT OUTER JOIN [dbo].[XSubDepartments] AS [Extent20] ON [Extent19].[SubDepartment_Id] = [Extent20].[Id]
            LEFT OUTER JOIN [dbo].[XLocations] AS [Extent21] ON [Extent18].[Location_Id] = [Extent21].[Id]
            WHERE [Extent19].[bsDepartmentId] < 90
        )  AS [Filter9]
        WHERE ([Filter9].[Department_Id] = @p__linq__0) AND (([Project9].[Id] = [Filter9].[Id1]) OR (([Project9].[Id] IS NULL) AND ([Filter9].[Id1] IS NULL)))) AS [C3]
    FROM ( SELECT 
        [Project8].[Id] AS [Id], 
        [Project8].[Name] AS [Name], 
        [Project8].[C1] AS [C1], 
        (SELECT 
            SUM([Filter7].[CurrentStock]) AS [A1]
            FROM ( SELECT [Extent14].[CurrentStock] AS [CurrentStock], [Extent16].[Department_Id] AS [Department_Id], [Extent17].[Id] AS [Id2]
                FROM    [dbo].[XStockLevels] AS [Extent14]
                INNER JOIN [dbo].[XProducts] AS [Extent15] ON [Extent14].[Product_Id] = [Extent15].[Id]
                LEFT OUTER JOIN [dbo].[XSubDepartments] AS [Extent16] ON [Extent15].[SubDepartment_Id] = [Extent16].[Id]
                LEFT OUTER JOIN [dbo].[XLocations] AS [Extent17] ON [Extent14].[Location_Id] = [Extent17].[Id]
                WHERE [Extent15].[bsDepartmentId] < 90
            )  AS [Filter7]
            WHERE ([Filter7].[Department_Id] = @p__linq__0) AND (([Project8].[Id] = [Filter7].[Id2]) OR (([Project8].[Id] IS NULL) AND ([Filter7].[Id2] IS NULL)))) AS [C2]
        FROM ( SELECT 
            [Project7].[Id] AS [Id], 
            [Extent13].[Name] AS [Name], 
            [Project7].[C1] AS [C1]
            FROM   (SELECT 
                [Project5].[Id] AS [Id], 
                [Project5].[C1] AS [C1], 
                (SELECT TOP (1) 
                    [Filter5].[Location_Id] AS [Location_Id]
                    FROM ( SELECT [Extent9].[Location_Id] AS [Location_Id], [Extent11].[Department_Id] AS [Department_Id], [Extent12].[Id] AS [Id3]
                        FROM    [dbo].[XStockLevels] AS [Extent9]
                        INNER JOIN [dbo].[XProducts] AS [Extent10] ON [Extent9].[Product_Id] = [Extent10].[Id]
                        LEFT OUTER JOIN [dbo].[XSubDepartments] AS [Extent11] ON [Extent10].[SubDepartment_Id] = [Extent11].[Id]
                        LEFT OUTER JOIN [dbo].[XLocations] AS [Extent12] ON [Extent9].[Location_Id] = [Extent12].[Id]
                        WHERE [Extent10].[bsDepartmentId] < 90
                    )  AS [Filter5]
                    WHERE ([Filter5].[Department_Id] = @p__linq__0) AND (([Project5].[Id] = [Filter5].[Id3]) OR (([Project5].[Id] IS NULL) AND ([Filter5].[Id3] IS NULL)))) AS [C2]
                FROM ( SELECT 
                    [Project4].[Id] AS [Id], 
                    [Project4].[C1] AS [C1]
                    FROM ( SELECT 
                        [Project2].[Id] AS [Id], 
                        (SELECT TOP (1) 
                            [Filter3].[Location_Id] AS [Location_Id]
                            FROM ( SELECT [Extent5].[Location_Id] AS [Location_Id], [Extent7].[Department_Id] AS [Department_Id], [Extent8].[Id] AS [Id4]
                                FROM    [dbo].[XStockLevels] AS [Extent5]
                                INNER JOIN [dbo].[XProducts] AS [Extent6] ON [Extent5].[Product_Id] = [Extent6].[Id]
                                LEFT OUTER JOIN [dbo].[XSubDepartments] AS [Extent7] ON [Extent6].[SubDepartment_Id] = [Extent7].[Id]
                                LEFT OUTER JOIN [dbo].[XLocations] AS [Extent8] ON [Extent5].[Location_Id] = [Extent8].[Id]
                                WHERE [Extent6].[bsDepartmentId] < 90
                            )  AS [Filter3]
                            WHERE ([Filter3].[Department_Id] = @p__linq__0) AND (([Project2].[Id] = [Filter3].[Id4]) OR (([Project2].[Id] IS NULL) AND ([Filter3].[Id4] IS NULL)))) AS [C1]
                        FROM ( SELECT 
                            [Distinct1].[Id] AS [Id]
                            FROM ( SELECT DISTINCT 
                                [Filter1].[Id5] AS [Id], 
                                [Filter1].[bsLocationId] AS [bsLocationId], 
                                [Filter1].[Name] AS [Name], 
                                [Filter1].[Code1] AS [Code1], 
                                [Filter1].[Code2] AS [Code2], 
                                [Filter1].[Code3] AS [Code3], 
                                [Filter1].[Code4] AS [Code4], 
                                [Filter1].[Code5] AS [Code5], 
                                [Filter1].[Code6] AS [Code6], 
                                [Filter1].[Code7] AS [Code7], 
                                [Filter1].[Code8] AS [Code8], 
                                [Filter1].[bsCompanyId] AS [bsCompanyId], 
                                [Filter1].[Group] AS [Group]
                                FROM ( SELECT [Extent3].[Department_Id] AS [Department_Id], [Extent4].[Id] AS [Id5], [Extent4].[bsLocationId] AS [bsLocationId], [Extent4].[Name] AS [Name], [Extent4].[Code1] AS [Code1], [Extent4].[Code2] AS [Code2], [Extent4].[Code3] AS [Code3], [Extent4].[Code4] AS [Code4], [Extent4].[Code5] AS [Code5], [Extent4].[Code6] AS [Code6], [Extent4].[Code7] AS [Code7], [Extent4].[Code8] AS [Code8], [Extent4].[bsCompanyId] AS [bsCompanyId], [Extent4].[Group] AS [Group]
                                    FROM    [dbo].[XStockLevels] AS [Extent1]
                                    INNER JOIN [dbo].[XProducts] AS [Extent2] ON [Extent1].[Product_Id] = [Extent2].[Id]
                                    LEFT OUTER JOIN [dbo].[XSubDepartments] AS [Extent3] ON [Extent2].[SubDepartment_Id] = [Extent3].[Id]
                                    LEFT OUTER JOIN [dbo].[XLocations] AS [Extent4] ON [Extent1].[Location_Id] = [Extent4].[Id]
                                    WHERE [Extent2].[bsDepartmentId] < 90
                                )  AS [Filter1]
                                WHERE [Filter1].[Department_Id] = @p__linq__0
                            )  AS [Distinct1]
                        )  AS [Project2]
                    )  AS [Project4]
                )  AS [Project5] ) AS [Project7]
            LEFT OUTER JOIN [dbo].[XLocations] AS [Extent13] ON [Project7].[C2] = [Extent13].[Id]
        )  AS [Project8]
    )  AS [Project9] ) AS [Project10]
LEFT OUTER JOIN  (SELECT 
    [Project15].[C1] AS [C1], 
    (SELECT 
        MAX([Extent28].[TransactionDate]) AS [A1]
        FROM   [dbo].[XSalesDetails] AS [Extent28]
        LEFT OUTER JOIN [dbo].[XProducts] AS [Extent29] ON [Extent28].[Product_Id] = [Extent29].[Id]
        INNER JOIN [dbo].[XSubDepartments] AS [Extent30] ON [Extent29].[SubDepartment_Id] = [Extent30].[Id]
        WHERE ([Extent30].[Department_Id] = @p__linq__1) AND (([Project15].[Location_Id] = [Extent28].[Location_Id]) OR (([Project15].[Location_Id] IS NULL) AND ([Extent28].[Location_Id] IS NULL)))) AS [C2]
    FROM ( SELECT 
        [Project14].[Location_Id] AS [Location_Id], 
        [Project14].[C1] AS [C1]
        FROM ( SELECT 
            [Project12].[Location_Id] AS [Location_Id], 
            (SELECT TOP (1) 
                [Extent25].[Location_Id] AS [Location_Id]
                FROM   [dbo].[XSalesDetails] AS [Extent25]
                LEFT OUTER JOIN [dbo].[XProducts] AS [Extent26] ON [Extent25].[Product_Id] = [Extent26].[Id]
                INNER JOIN [dbo].[XSubDepartments] AS [Extent27] ON [Extent26].[SubDepartment_Id] = [Extent27].[Id]
                WHERE ([Extent27].[Department_Id] = @p__linq__1) AND (([Project12].[Location_Id] = [Extent25].[Location_Id]) OR (([Project12].[Location_Id] IS NULL) AND ([Extent25].[Location_Id] IS NULL)))) AS [C1]
            FROM ( SELECT 
                @p__linq__1 AS [p__linq__1], 
                [Distinct2].[Location_Id] AS [Location_Id]
                FROM ( SELECT DISTINCT 
                    [Extent22].[Location_Id] AS [Location_Id]
                    FROM   [dbo].[XSalesDetails] AS [Extent22]
                    LEFT OUTER JOIN [dbo].[XProducts] AS [Extent23] ON [Extent22].[Product_Id] = [Extent23].[Id]
                    INNER JOIN [dbo].[XSubDepartments] AS [Extent24] ON [Extent23].[SubDepartment_Id] = [Extent24].[Id]
                    WHERE [Extent24].[Department_Id] = @p__linq__1
                )  AS [Distinct2]
            )  AS [Project12]
        )  AS [Project14]
    )  AS [Project15] ) AS [Project16] ON ([Project10].[C1] = [Project16].[C1]) OR (([Project10].[C1] IS NULL) AND ([Project16].[C1] IS NULL))
DECLARE @DeptId INT = 1;

SELECT Location_Id, XLocations.Name, CurrentStock, LastInvoice, LastSale
FROM
(SELECT Location_Id, SUM(CurrentStock) AS CurrentStock, MAX(LastInvoice) AS LastInvoice, MAX(LastSale) AS LastSale
   FROM XStockLevels
LEFT JOIN 
(SELECT XProducts.bsDepartmentId, XProducts.bsSubDepartmentId, XProducts.bsItemId, XProducts.Id, LastSale
   FROM XProducts 
  INNER JOIN XSubDepartments ON XProducts.SubDepartment_Id = XSubDepartments.Id
   LEFT JOIN (SELECT Product_Id, MAX(TransactionDate) AS LastSale FROM XSalesDetails GROUP BY Product_Id) XSD ON XSD.Product_Id = XProducts.Id
  WHERE XProducts.bsDepartmentId<90 AND XSubDepartments.Department_Id = @DeptId) XP
ON XStockLevels.Product_Id = XP.Id
GROUP BY Location_Id) Z 
INNER JOIN XLocations ON Z.Location_Id = XLocations.Id
    var query5 = (
        from sl in (
            (from xsl in slRepo
                where
                    xsl.Product.bsDepartmentId < 90 &&
                    xsl.Product.SubDepartment.Department.Id == 1
                group xsl by new
                {
                    xsl.Location.Id
                }
                into g
                select new
                {
                    g.Key,
                    LocationId = g.Key.Id,
                    CurrentStock = (int?) g.Sum(p => p.CurrentStock),
                    LastInvoice = g.Max(p => p.LastInvoice)
                }))
        join ls in (
            (from xsd in sdRepo
                join xp in prodRepo on xsd.Product.Id equals xp.Id into xpJoin
                from xp in xpJoin.DefaultIfEmpty()
                join xs in subDepRepo on xp.SubDepartment.Id equals xs.Id into xsJoin
                from xs in xsJoin.DefaultIfEmpty()
                where
                    xp.bsDepartmentId < 90 &&
                    xs.Department.Id == 1
                group xsd by new
                {
                    xsd.Location.Id
                }
                into g
                select new
                {
                    g.Key,
                    LastSale = (DateTime?)g.Max(p => p.TransactionDate)
                })) on sl.Key equals ls.Key into lsJoin
        from ls in lsJoin.DefaultIfEmpty()
        join l in locRepo on sl.LocationId equals l.Id
        select new XStockOverviewDto
        {
            Location = l.Name,
            Quantity = sl.CurrentStock,
            LastInvoice = sl.LastInvoice,
            LastSale = ls.LastSale
        });
SELECT 
    1 AS [C1], 
    [Extent7].[Name] AS [Name], 
    [GroupBy1].[A1] AS [C2], 
    [GroupBy1].[A2] AS [C3], 
    CASE WHEN ([Project1].[C2] IS NULL) THEN CAST(NULL AS datetime2) ELSE  CAST( [Project1].[C1] AS datetime2) END AS [C4]
    FROM    (SELECT 
        [Filter1].[Location_Id] AS [K1], 
        SUM([Filter1].[CurrentStock]) AS [A1], 
        MAX([Filter1].[LastInvoice]) AS [A2]
        FROM ( SELECT [Extent1].[CurrentStock] AS [CurrentStock], [Extent1].[LastInvoice] AS [LastInvoice], [Extent1].[Location_Id] AS [Location_Id], [Extent3].[Department_Id] AS [Department_Id]
            FROM   [dbo].[XStockLevels] AS [Extent1]
            INNER JOIN [dbo].[XProducts] AS [Extent2] ON [Extent1].[Product_Id] = [Extent2].[Id]
            INNER JOIN [dbo].[XSubDepartments] AS [Extent3] ON [Extent2].[SubDepartment_Id] = [Extent3].[Id]
            WHERE [Extent2].[bsDepartmentId] < 90
        )  AS [Filter1]
        WHERE 1 = [Filter1].[Department_Id]
        GROUP BY [Filter1].[Location_Id] ) AS [GroupBy1]
    LEFT OUTER JOIN  (SELECT 
        [GroupBy2].[K1] AS [Location_Id], 
        [GroupBy2].[A1] AS [C1], 
        1 AS [C2]
        FROM ( SELECT 
            [Filter3].[Location_Id] AS [K1], 
            MAX([Filter3].[TransactionDate]) AS [A1]
            FROM ( SELECT [Extent4].[TransactionDate] AS [TransactionDate], [Extent4].[Location_Id] AS [Location_Id], [Extent6].[Department_Id] AS [Department_Id]
                FROM   [dbo].[XSalesDetails] AS [Extent4]
                INNER JOIN [dbo].[XProducts] AS [Extent5] ON [Extent4].[Product_Id] = [Extent5].[Id]
                INNER JOIN [dbo].[XSubDepartments] AS [Extent6] ON [Extent5].[SubDepartment_Id] = [Extent6].[Id]
                WHERE [Extent5].[bsDepartmentId] < 90
            )  AS [Filter3]
            WHERE 1 = [Filter3].[Department_Id]
            GROUP BY [Filter3].[Location_Id]
        )  AS [GroupBy2] ) AS [Project1] ON ([GroupBy1].[K1] = [Project1].[Location_Id]) OR (([GroupBy1].[K1] IS NULL) AND ([Project1].[Location_Id] IS NULL))
    INNER JOIN [dbo].[XLocations] AS [Extent7] ON [GroupBy1].[K1] = [Extent7].[Id]
gbsl.FirstOrDefault().Location.Id
gbsl.Key.Id