2009-04-28 9 views
12

Unten sind zwei Abfragen, die die gleichen Daten zurückgeben. Andere als Stil Ich bin mir nicht sicher, was besser ist.Was ist der Unterschied zwischen LINQ-Abfrageausdrücken und Erweiterungsmethoden?

Welche Faktoren beeinflussen diese Abfragen? Was sind die Vorteile der Verwendung eines Stils gegenüber dem anderen?

Beispiel 1

var x = from s in db.Surveys 
    join sq in db.Survey_Questions on s.ID equals sq.Survey_ID 
    join q in db.Questions on sq.Question_ID equals q.ID 
    join qg in db.Question_Groups on q.ID equals qg.Question_ID 
    where s.Type_ID.Equals(typeID) & s.Type.Equals(type) 
    select new { question = sq.Question, status = sq.Status, grp = qg }; 

Probe 2

var x = db.Surveys.Where(s => s.Type_ID.Equals(typeID) & s.Type.Equals(type)) 
       .Join(db.Survey_Questions, 
         s => s.ID, 
         sq => sq.Survey_ID, 
         (s, sq) => new 
         { 
          question = sq.Question, 
          status = sq.Status 
         }) 
       .Join(db.Question_Groups, 
         q => q.question.ID, 
         qg => qg.Question_ID, 
         (q, qg) => new 
         { 
          question = q.question, 
          status = q.status, 
          group = qg 
         }).ToList(); 
+0

seine erwähnenswert Ihre Proben sind nicht für nicht identisch ... –

+0

Auch die .ToList() am Ende Kräfte ganz andere Ausführung. Lassen Sie sie aus, um sie äquivalent zu machen. Das erste x ist vom Typ IQueryable und das zweite ist IList . –

Antwort

19

Update: Sie haben Ihren Titel behoben, also ignorieren Sie die Rant.

Der Titel Ihrer Frage hat nichts mit Ihren Codebeispielen zu tun. Ihre Frage impliziert, dass eine Syntax IEnumerable und die andere IQueryable ist, aber das ist falsch. Wenn in Ihren Beispielen db.Surveys ein IQueryable ist, dann beide Ihre Proben verwenden IQueryable. Ich werde versuchen, beide Fragen zu beantworten.

Ihre beiden Codebeispiele sind nur unterschiedliche Möglichkeiten zum Schreiben der gleichen LINQ-Abfragen (vorausgesetzt, sie sind gut geschrieben). Der Code in Beispiel 1 ist nur eine Kurzform für den Code in Beispiel 2. Der Compiler behandelt den Code in beiden Beispielen auf die gleiche Weise. Denken Sie an die Art und Weise, wie der C# -Compiler int? genauso behandelt wie Nullable<System.Int32>. Sowohl die C# - als auch die VB.Net-Sprachen stellen diese Abkürzungssyntax bereit. Andere Sprachen haben möglicherweise diese Syntax nicht und Sie müssten die Syntax von Beispiel 2 verwenden. Tatsächlich unterstützen andere Sprachen möglicherweise nicht einmal Erweiterungsmethoden oder Lambda-Ausdrücke, und Sie müssten noch eine hässlichere Syntax verwenden.


Update:

Um Sander Beispiel zu nehmen, wenn Sie diese (Abfrage-Syntax) schreiben:

var surveyNames = from s in db.Surveys select s.Name 

Sie denken, der Compiler dreht, dass eine Abkürzung in diese (Erweiterungsmethoden und Lambda-Ausdruck):

IQueryable<string> surveryNames = db.Surveys.Select(s => s.Name); 

Aber eigentlich sind Erweiterungsmethoden und Lambda-Ausdrücke selbst Kürzel.Die Compiler emittieren so etwas wie diese (nicht genau, aber nur eine Idee zu geben):

Expression<Func<Survey, string>> selector = delegate(Survey s) { return s.Name; }; 
IQueryable<string> surveryNames = Queryable.Select(db.Surveys, selector); 

Beachten Sie, dass Select() ist nur eine statische Methode in der Queryable Klasse. Wenn Ihre .NET-Sprache keine Abfragesyntax, Lambdas oder Erweiterungsmethoden unterstützt, müssen Sie den Code selbst schreiben.


Was sind die Vorteile von einem Stil über die andere verwenden?

Für kleine Abfragen Erweiterungsmethoden kann kompakter sein:

var items = source.Where(s => s > 5); 

Auch kann die Erweiterungsmethode Syntax flexibler sein, wie bedingte WHERE-Klauseln:

var items = source.Where(s => s > 5); 

if(smallerThanThen) 
    items = items.Where(s => s < 10); 
if(even) 
    items = items.Where(s => (s % 2) == 0); 

return items.OrderBy(s => s); 

Zusätzlich , mehrere Methoden sind nur über die Syntax der Erweiterungsmethode (Count(), Aggregate(), Take(), Skip(), ToList(), ToArray() usw.) verfügbar. Wenn ich also eines davon verwende, In der Regel schreibe ich die gesamte Abfrage in diese Syntax, um eine Vermischung zu vermeiden. b andere Syntaxen.

var floridaCount = source.Count(s => s.State == "FL"); 

var items = source 
      .Where(s => s > 5) 
      .Skip(5) 
      .Take(3) 
      .ToList(); 

Auf der anderen Seite, wenn eine Abfrage größer und komplexer wird, Abfrage-Syntax kann klarer sein, vor allem, wenn Sie mit ein paar let, group, join usw.

In der verkomplizieren starten Ende werde ich normalerweise verwenden, was für jede spezifische Abfrage besser funktioniert.


Update: Sie Ihren Titel festgelegt, so ignoriert den Rest ...

Nun, über Ihren Titel: In Bezug auf LINQ, IEnumerable und IQueryable sind sehr ähnlich. Sie haben beide die gleichen Erweiterungsmethoden (Select, Where, Count, usw.), wobei der Hauptunterschied (nur?) Darin besteht, dass IEnumerable Func<TIn,TOut> als Parameter und IQueryable Expression<Func<TIn,TOut>> als Parameter verwendet. Sie drücken beide den gleichen Weg aus (normalerweise Lamba-Ausdrücke), aber innerlich sind sie völlig verschieden.

IEnumerable ist der Eingang zu LINQ to Objects. Die LINQ to Objects-Erweiterungsmethoden können auf jedem IEnumerable (Arrays, Listen, alles, was Sie mit iterieren können) aufgerufen werden, und die Func<TIn,TOut> wird zur Kompilierungszeit in IL konvertiert und läuft zur Laufzeit wie ein normaler Methodencode. Beachten Sie, dass einige andere LINQ-Anbieter IEnumerable verwenden und daher LINQ to Objects im Hintergrund verwenden (LINQ to XML, LINQ to DataSet).

IQQueryable wird von LINQ to SQL, LINQ to Entities und anderen LINQ-Anbietern verwendet, die Ihre Abfrage untersuchen und übersetzen müssen, anstatt den Code direkt auszuführen. IQueryable-Abfragen und ihre Expression<Func<TIn,TOut>> s werden zur Kompilierungszeit nicht in IL kompiliert. Stattdessen wird ein Ausdrucksbaum erstellt und kann zur Laufzeit untersucht werden. Dadurch können die Anweisungen in andere Abfragesprachen (z. B. T-SQL) übersetzt werden. Ein Ausdrucksbaum kann zur Laufzeit in eine Func < TIn, TOut > kompiliert und bei Bedarf ausgeführt werden.

Ein Beispiel, das den Unterschied veranschaulicht, finden Sie unter this question, wo das OP einen Teil einer LINQ to SQL-Abfrage in SQL Server ausführen, die Objekte in verwalteten Code bringen und den Rest der Abfrage in LINQ to Objects erledigen soll . Um dies zu erreichen, muss er nur das IQueryable in ein IEnumerable umwandeln, wo er den Wechsel durchführen möchte.

3

LINQ ist Schlagwort für eine Technologie.

IQueryable ist eine .NET-Schnittstelle, die von LINQ verwendet wird.

Abgesehen vom Stil gibt es keinen Unterschied zwischen den beiden. Verwenden Sie den von Ihnen bevorzugten Stil.

Ich bevorzuge den ersten Stil für lange Aussage (wie hier gezeigt) und den zweiten für sehr kurze Aussagen.

0

Ich glaube, Ihre Frage besser so formuliert ist,

LINQ-Abfragen "Was ist der Unterschied zwischen IEnumerable <T> und IQueryable <T> in Bezug auf LINQ ist" Rückkehr ein IQueryable <T> standardmäßig. IQueryable <T> können Sie andere Filter oder "Klauseln" an Ihre Abfrage anhängen, bevor Sie es ausführen.

Ihre LINQ-Abfrage (erstes Beispiel) und Ihr LINQ mit Methodenverkettung (zweites Beispiel) erzeugen das gleiche Ergebnis mit unterschiedlicher Syntax.

Es ist möglich, eine LINQ-Abfrage als eine LINQ-Methodenkette zu schreiben und umgekehrt. Es hängt wirklich von deiner Vorliebe ab.

@Lucas: Das unterscheidet IEnumerable <T> tut In-Memory-Abfrage- und IQueryable <T> tut out-of-memory. Das heißt, sobald Sie in einem foreach Iterator sind, verwenden Sie IEnumerable, und wenn Sie Ihre Abfrage erstellen, entweder über Erweiterungsmethoden oder mithilfe von LINQ from o in object Synatax, erstellen Sie ein IQueryable <T>. Das IQueryable <T> wird ausgeführt, sobald Sie den Enumerator berühren.

+0

"LINQ-Abfragen geben standardmäßig ein IQueryable zurück." Sie meinen LINQ to SQL oder LINQ to Entities. LINQ to Objects verwendet IEnumerable – Lucas

+0

"IQueryable können Sie andere Filter oder" Klauseln "an Ihre Abfrage anhängen, bevor Sie es ausführen." So tut IEnumerable. – Lucas

+0

oh und der Titel der Frage wurde behoben :) – Lucas

1

1./Ihr Fragentitel stimmt nicht mit Ihren Fragen überein.
2./Ihr Fragetitel macht keinen Sinn. Linq steht für Language Integrated Query und ist ein Überbegriff für eine Reihe von Technologien und Praktiken. IQueryable ist eine Schnittstelle, die häufig verwendet wird, um Linq zu erleichtern. Sie vergleichen Äpfel und Orangen
3./Über Ihre eigentliche Frage, der Hauptunterschied ist Stil, für komplexe Abfragen wie diese, meine persönliche Präferenz ist die 2. Version, wie es deutlich zeigt die Progression der Ergebnissätze.

2

Die where-Klausel im ersten Beispiel ist eigentlich nur syntaktischer Zucker für die Where-Klausel in Ihrer zweiten Methode. In der Tat können Sie Ihre eigene Klasse schreiben, die nichts mit Linq oder IQueryable zu tun hat, und nur mit einer Where-Methode können Sie diesen syntaktischen Zucker verwenden.Zum Beispiel:

public class MyClass 
    { 

     public MyClass Where<T>(Func<MyClass, T> predicate) 
     { 
      return new MyClass { StringProp = "Hello World" }; 
     } 

     public MyClass Select<T>(Func<MyClass, T> predicate) 
     { 
      return new MyClass(); 
     } 



     public string StringProp { get; set; } 
    } 

Das ist natürlich ein dummes Beispiel, beachten Sie aber, dass es eine Wo-Methode, die gerade eine neue MyClass mit stringprop zu Hallo Welt gesetzt zurückzugibt. Um zu demonstrieren:

MyClass a = new MyClass(); 
      var q = from p in a 
        where p.StringProp == "foo" // doesnt matter what we put here, as we're not really checking the predicate 
        select p; 
      Console.WriteLine(q.StringProp); 

Dies wird zur Folge haben, schriftlich out "Hallo Welt". Auch dieses Beispiel ist offensichtlich sinnlos, aber es beweist, dass die "where" -Syntax nur nach einer Where-Methode in Ihrem Code sucht, die einen Func benötigt.

2

Abfrageausdrücke und Erweiterungsmethoden sind zwei Möglichkeiten, genau dasselbe zu tun. Query-Ausdrücke werden beim Compilieren in Erweiterungsmethoden umgewandelt - sie sind nur syntaktische Zucker für Leute, die mit SQL besser vertraut sind.

Wenn Sie schreiben dies:

var surveyNames = from s in db.Surveys select s.Name; 

Der Compiler wandelt diese in:

IQueryable<string> surveryNames = db.Surveys.Select(s => s.Name); 

Wirklich, ich glaube Abfrage Ausdrücke wurden nur aus Marketinggründen erstellt - ein SQL-ähnlichen Sprachkonstrukt zu handeln als Eyecatcher, als LINQ entwickelt wurde, nicht etwas, das viel tatsächlichen Nutzen bietet. Ich finde, dass die meisten Leute die Erweiterungsmethoden direkt verwenden, da sie einen einheitlicheren Codierungsstil anstelle einer Mischung aus C# und SQL ergeben.

1

Ihre Sample1 ist Top-Level-Darstellung von Linq, es ist besser lesbar, und während es wird d.h Ihre Sample2 zum Ausdruck Baum umgewandelt kompilieren.

var x = from s in db.Surveys 
    join sq in db.Survey_Questions on s.ID equals sq.Survey_ID 
    join q in db.Questions on sq.Question_ID equals q.ID 
    join qg in db.Question_Groups on q.ID equals qg.Question_ID 
    where s.Type_ID.Equals(typeID) & s.Type.Equals(type) 
    select new { question = sq.Question, status = sq.Status, grp = qg }; 

können Sie unter Code versuchen Ausdruck für schriftliche Abfrage

var exp=x.Expression; 

Ausdrücke verwendet, zu erhalten, wenn Abfrage weniger kompliziert

0

Ein weiterer Punkt ist erwähnenswert, dass die Linq Erweiterungsmethoden Sprache C# haften während das Query-Verständnis-Zeug wie im Compiler eingebaut vorverarbeitet wird. dh Sie auf die Definition von .Select navigieren können (x => während Sie from ... where ... select

Verwandte Themen