简体   繁体   English

这些LINQ查询之间有什么区别

[英]What is the difference between these LINQ queries

I've been fooling around with some LINQ over Entities and I'm getting strange results and I would like to get an explanation... 我一直在使用一些LINQ over Entities,我得到了奇怪的结果,我想得到解释......

Given the following LINQ query, 给出以下LINQ查询,

// Sample # 1
IEnumerable<GroupInformation> groupingInfo;
groupingInfo = from a in context.AccountingTransaction
               group a by a.Type into grp
               select new GroupInformation()
               {
                   GroupName = grp.Key,
                   GroupCount = grp.Count()
               };

I get the following SQL query (taken from SQL Profiler): 我得到以下SQL查询(取自SQL Profiler):

SELECT 
    1 AS [C1], 
    [GroupBy1].[K1] AS [Type], 
    [GroupBy1].[A1] AS [C2]
    FROM ( SELECT 
        [Extent1].[Type] AS [K1], 
        COUNT(1) AS [A1]
        FROM [dbo].[AccountingTransaction] AS [Extent1]
        GROUP BY [Extent1].[Type]
    )  AS [GroupBy1]

So far so good. 到现在为止还挺好。

If I change my LINQ query to: 如果我将我的LINQ查询更改为:

// Sample # 2
groupingInfo = context.AccountingTransaction.
                 GroupBy(a => a.Type).
                 Select(grp => new GroupInformation()
                               {
                                   GroupName = grp.Key,
                                   GroupCount = grp.Count()
                               });

it yields to the exact same SQL query. 它产生完全相同的SQL查询。 Makes sense to me. 我感觉合理。

Here comes the interesting part... If I change my LINQ query to: 这是有趣的部分...如果我将我的LINQ查询更改为:

// Sample # 3
IEnumerable<AccountingTransaction> accounts;
IEnumerable<IGrouping<object, AccountingTransaction>> groups;
IEnumerable<GroupInformation> groupingInfo;

accounts = context.AccountingTransaction;
groups = accounts.GroupBy(a => a.Type);
groupingInfo = groups.Select(grp => new GroupInformation()
                  {
                      GroupName = grp.Key,
                      GroupCount = grp.Count()
                  });

the following SQL is executed (I stripped a few of the fields from the actual query, but all the fields from the table (~ 15 fields) were included in the query, twice): 执行以下SQL(我从实际查询中删除了一些字段,但表中的所有字段(~15个字段)都包含在查询中,两次):

SELECT 
    [Project2].[C1] AS [C1], 
    [Project2].[Type] AS [Type], 
    [Project2].[C2] AS [C2], 
    [Project2].[Id] AS [Id], 
    [Project2].[TimeStamp] AS [TimeStamp], 
    -- <snip>
    FROM ( SELECT 
        [Distinct1].[Type] AS [Type], 
        1 AS [C1], 
        [Extent2].[Id] AS [Id], 
        [Extent2].[TimeStamp] AS [TimeStamp], 
        -- <snip>
        CASE WHEN ([Extent2].[Id] IS NULL) THEN CAST(NULL AS int) ELSE 1 END AS [C2]
        FROM   (SELECT DISTINCT 
            [Extent1].[Type] AS [Type]
            FROM [dbo].[AccountingTransaction] AS [Extent1] ) AS [Distinct1]
        LEFT OUTER JOIN [dbo].[AccountingTransaction] AS [Extent2] ON [Distinct1].[Type] = [Extent2].[Type]
    )  AS [Project2]
    ORDER BY [Project2].[Type] ASC, [Project2].[C2] ASC

Why are the SQLs generated are so different? 为什么生成的SQL如此不同? After all, the exact same code is executed, it's just that sample # 3 is using intermediate variables to get the same job done! 毕竟,执行完全相同的代码,只是示例#3使用中间变量来完成相同的工作!

Also, if I do: 另外,如果我这样做:

Console.WriteLine(groupingInfo.ToString());

for sample # 1 and sample # 2, I get the exact same query that was captured by SQL Profiler, but for sample # 3, I get: 对于示例#1和示例#2,我得到了与SQL事件探查器捕获的完全相同的查询,但对于示例#3,我得到:

System.Linq.Enumerable+WhereSelectEnumerableIterator`2[System.Linq.IGrouping`2[System.Object,TestLinq.AccountingTransaction],TestLinq.GroupInformation]

What is the difference? 有什么不同? Why can't I get the SQL Query generated by LINQ if I split the LINQ query in multiple instructions? 如果我在多个指令中拆分LINQ查询,为什么我不能获得LINQ生成的SQL查询?

The ulitmate goal is to be able to add operators to the query (Where, OrderBy, etc.) at run-time. ulitmate的目标是能够在运行时向查询(Where,OrderBy等)添加运算符。

BTW, I've seen this behavior in EF 4.0 and EF 6.0. 顺便说一下,我在EF 4.0和EF 6.0中看到过这种行为。

Thank you for your help. 谢谢您的帮助。

The reason is because in your third attempt you're referring to accounts as IEnumerable<AccountingTransaction> which will cause the query to be invoked using Linq-To-Objects ( Enumerable.GroupBy and Enumerable.Select ) 原因是因为在您的第三次尝试中,您将accounts称为IEnumerable<AccountingTransaction> ,这将导致使用Linq-To-ObjectsEnumerable.GroupByEnumerable.Select )调用查询

On the other hand, in your first and second attempts the reference to AccountingTransaction is preserved as IQueryable<AccountingTransaction> and the query will be executed using Linq-To-Entities which will then transform it to the appropriate SQL statement. 另一方面,在第一次和第二次尝试中,对AccountingTransaction的引用保留为IQueryable<AccountingTransaction>并且将使用Linq-To-Entities执行查询,然后Linq-To-Entities将其转换为适当的SQL语句。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM