6

ho scherzare con alcuni LINQ su soggetti e sto ottenendo risultati strani e mi piacerebbe ottenere una spiegazione ...Qual è la differenza tra questi LINQ interroga

Data la seguente 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() 
       }; 

ottengo la seguente query SQL (tratto da 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] 

Fin qui tutto bene.

Se cambio il mio query LINQ a:

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

cede per la stessa query SQL. Ha senso per me.

Qui viene la parte interessante ... Se cambio la mia query LINQ a:

// 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() 
        }); 

viene eseguito il seguente SQL (ho messo a nudo alcuni dei campi dalla query reale, ma tutti i campi la tabella (~ 15 campi) sono stati inclusi nella query, due volte):

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 

Perché gli SQL generati sono così diversi? Dopotutto, viene eseguito lo stesso codice esatto, è solo che il campione n. 3 utilizza variabili intermedie per ottenere lo stesso risultato!

Inoltre, se faccio:

Console.WriteLine(groupingInfo.ToString()); 

per il campione # 1 e il campione # 2, ottengo la stessa identica domanda che è stato catturato da SQL Profiler, ma per il campione # 3, ottengo:

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

Qual è la differenza? Perché non riesco a ottenere la query SQL generata da LINQ se divido la query LINQ in più istruzioni?

L'obiettivo ultraresistente è poter aggiungere operatori alla query (Where, OrderBy, ecc.) In fase di esecuzione.

BTW, ho visto questo comportamento in EF 4.0 e EF 6.0.

Grazie per il vostro aiuto.

+3

Non riesco nemmeno a capire una ragione per cui qualcuno potrebbe averlo svalutato. Spiegare? – Yuck

risposta

7

Il motivo è perché nel vostro terzo tentativo ti riferisci accounts come IEnumerable<AccountingTransaction> che farà sì che la query da richiamare utilizzando LINQ to Objects (Enumerable.GroupBy e Enumerable.Select)

D'altra parte, nei primi e secondi tentativi il riferimento a AccountingTransaction viene mantenuto come IQueryable<AccountingTransaction> e la query verrà eseguita utilizzando Linq-To-Entities che verrà quindi trasformata nell'istruzione SQL appropriata.

+0

Quindi 'groups = accounts.GroupBy (a => a.Type). AsQueryable();' fai il trucco? O semplicemente usando 'var' per le dichiarazioni delle variabili? – Yuck

+1

'accounts.AsQueryable(). GroupBy (a => a.Type)' farà. – haim770

+0

o solo 'var accounts = context.AccountingTransaction; '... – Magnus

Problemi correlati