6

Ich habe mit einigen LINQ über Entities herum täuscht und ich bin immer seltsame Ergebnisse, und ich möchte eine Erklärung bekommen ...Was ist der Unterschied zwischen diesen LINQ-Abfragen

die folgende LINQ-Abfrage gegeben,

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

erhalte ich die folgende SQL-Abfrage (aus 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 weit so gut.

Wenn ich meine LINQ-Abfrage zu ändern:

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

es ergibt sich auf die exakt gleiche SQL-Abfrage. Für mich ergibt das Sinn.

Hier kommt der interessante Teil ... Wenn ich meine LINQ-Abfrage zu ändern:

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

die folgende SQL ausgeführt wird (ich einige der Felder aus der aktuellen Abfrage gestrippt, aber alle Felder aus die Tabelle (~ 15 Felder) wurden zweimal in die Abfrage aufgenommen:

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 

Warum sind die erzeugten SQL-Dateien so unterschiedlich? Schließlich wird genau derselbe Code ausgeführt, nur dass Beispiel 3 Zwischenvariablen verwendet, um die gleiche Aufgabe zu erledigen!

Auch, wenn ich tun:

Console.WriteLine(groupingInfo.ToString()); 

für Probe # 1 und Probe # 2, bekomme ich genau die gleiche Abfrage, die drei von SQL Profiler, aber für die Probe # gefangen genommen wurde, erhalte ich:

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

Was ist der Unterschied? Warum kann ich die von LINQ generierte SQL-Abfrage nicht erhalten, wenn ich die LINQ-Abfrage in mehrere Anweisungen aufspalte?

Das ultimative Ziel besteht darin, Operatoren zu der Abfrage (Where, OrderBy usw.) zur Laufzeit hinzuzufügen.

BTW, ich habe dieses Verhalten in EF 4.0 und EF 6.0 gesehen.

Vielen Dank für Ihre Hilfe.

+3

Ich kann nicht einmal einen Grund ausloten, warum jemand das hätte abwerten können. Erklären? – Yuck

Antwort

7

Der Grund ist, weil in Ihrem dritten Versuch sind Sie auf accounts als IEnumerable<AccountingTransaction> bezieht, die die Abfrage verursachen

Auf der anderen Seite aufgerufen mit Linq-To-Objekte (Enumerable.GroupBy und Enumerable.Select) werden, Bei Ihrem ersten und zweiten Versuch wird der Verweis auf AccountingTransaction als IQueryable<AccountingTransaction> beibehalten und die Abfrage wird unter Verwendung von Linq-To-Entities ausgeführt, die sie dann in die entsprechende SQL-Anweisung transformieren.

+0

So würde 'groups = accounts.GroupBy (a => a.Type) .AsQueryable();' den Trick? Oder einfach 'var' für die Variablendeklarationen verwenden? – Yuck

+1

'accounts.AsQueryable(). GroupBy (a => a.Type)' wird tun. – haim770

+0

oder einfach 'var accounts = context.AccountingTransaction; '... – Magnus

Verwandte Themen