14 Stimmen

Was ist der Unterschied zwischen LINQ-Abfrageausdrücken und Erweiterungsmethoden?

Nachfolgend finden Sie zwei Abfragen, die die gleichen Daten liefern. Abgesehen vom Stil bin ich mir nicht sicher, welche besser ist.

Welche Faktoren beeinflussen diese Abfragen? Welche Vorteile hat die Verwendung des einen Stils gegenüber dem anderen?

Muster 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 };

Beispiel 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 Stimmen

Es ist erwähnenswert, dass Ihre Proben nicht identisch sind ...

0 Stimmen

Auch das .ToList() am Ende erzwingt eine ganz andere Ausführung. Lassen Sie es weg, um sie gleichwertig zu machen. Das erste x ist vom Typ IQueryable<T> und das zweite ist IList<T>.

24voto

Lucas Punkte 16934

Update: Sie haben Ihren Titel korrigiert, also ignorieren Sie die Schimpftirade.

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. In Ihren Beispielen, wenn db.Surveys ein IQueryable ist, dann beide Ihre Beispiele sind mit IQueryable. Ich werde versuchen zu antworten beide Fragen.

Ihre beiden Codebeispiele sind nur verschiedene Möglichkeiten, die gleichen LINQ-Abfragen zu schreiben (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 dieselbe Weise. Denken Sie an die Art und Weise, wie der C#-Compiler Folgendes behandeln wird int? dasselbe wie Nullable<System.Int32> . Sowohl die Sprachen C# als auch VB.Net bieten diese Kurzabfragesyntax. Andere Sprachen verfügen möglicherweise nicht über diese Syntax und Sie müssen die Syntax von Beispiel 2 verwenden. Andere Sprachen unterstützen möglicherweise nicht einmal Erweiterungsmethoden oder Lambda-Ausdrücke, und Sie müssten eine noch hässlichere Syntax verwenden.


Update:

Um das Beispiel von Sander weiterzuführen: Wenn Sie dies schreiben (Syntax für Abfrageverständnis):

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

Sie denken verwandelt der Compiler diese Abkürzung in das hier (Erweiterungsmethoden und Lambda-Ausdruck):

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

Aber eigentlich sind Erweiterungsmethoden und Lambda-Ausdrücke selbst Kurzschrift. Der Compiler gibt so etwas aus (nicht genau, aber nur um eine Vorstellung zu vermitteln):

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

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


Welche Vorteile hat der eine Stil gegenüber dem anderen?

Bei kleinen Abfragen können die Erweiterungsmethoden kompakter sein:

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

Außerdem kann die Syntax der Erweiterungsmethode flexibler sein, z. B. durch 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);

Außerdem sind mehrere Methoden nur über die Syntax der Erweiterungsmethoden verfügbar (Count(), Aggregate(), Take(), Skip(), ToList(), ToArray() usw.). Wenn ich also eine dieser Methoden verwende, schreibe ich normalerweise die gesamte Abfrage in dieser Syntax, damit ich nicht beide Syntaxen vermische.

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

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

Andererseits, wenn eine Abfrage größer und komplexer wird, kann die Abfrageverstehenssyntax klarer sein, vor allem, wenn man anfängt, sie mit ein paar let , group , join , usw.

Am Ende verwende ich in der Regel das, was für die jeweilige Anfrage am besten geeignet ist.


Update: Sie haben Ihren Titel korrigiert, also ignorieren Sie den Rest...

Nun zu Ihrem Titel: In Bezug auf LINQ sind IEnumerable und IQueryable sehr ähnlich. Sie haben beide so ziemlich die gleichen Erweiterungsmethoden (Select, Where, Count, etc.), wobei der wichtigste (einzige?) Unterschied darin besteht, dass IEnumerable Func<TIn,TOut> als Paremeter und IQueryable nimmt Expression<Func<TIn,TOut>> als Parameter. Man drückt beide auf die gleiche Weise aus (in der Regel durch Lamba-Ausdrücke), aber intern sind sie völlig unterschiedlich.

IEnumerable ist das Tor zu LINQ to Objects. Die LINQ to Objects-Erweiterungsmethoden können mit jeder IEnumerable aufgerufen werden (Arrays, Listen, alles, mit dem man iterieren kann foreach ) und die Func<TIn,TOut> wird zur Kompilierzeit in IL umgewandelt und läuft zur Laufzeit wie ein normaler Methodencode. Beachten Sie, dass einige andere LINQ-Anbieter IEnumerable verwenden und somit hinter den Kulissen tatsächlich LINQ to Objects verwenden (LINQ to XML, LINQ to DataSet).

IQueryable wird von LINQ to SQL, LINQ to Entities und anderen LINQ-Anbietern verwendet, die Ihre Abfrage untersuchen und übersetzen müssen, anstatt Ihren Code direkt auszuführen. IQueryable-Abfragen und ihre Expression<Func<TIn,TOut>> s werden zur Kompilierzeit nicht in AWL kompiliert. Stattdessen wird eine Ausdrucksbaum wird erstellt und kann zur Laufzeit überprüft 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 auf Wunsch ausgeführt werden.

Ein Beispiel, das den Unterschied verdeutlicht, findet sich in この質問 wo der OP einen Teil einer LINQ to SQL-Abfrage in SQL Server ausführen möchte, die Objekte in verwalteten Code bringen und den Rest der Abfrage in LINQ to Objects ausführen möchte. Um dies zu erreichen, muss er nur die IQueryable in eine IEnumerable umwandeln, wo er den Wechsel durchführen möchte.

4voto

James Curran Punkte 98228

LINQ ist ein Modewort 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 Stil, den Sie bevorzugen.

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

2voto

BFree Punkte 100035

Die Where-Klausel im ersten Beispiel ist eigentlich nur syntaktischer Zucker für die Where-Klausel in Ihrer zweiten Methode. Tatsächlich können Sie Ihre eigene Klasse schreiben, die nichts mit Linq oder IQueryable zu tun hat, und nur durch eine 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; }
    }

Dies ist natürlich ein dummes Beispiel, aber beachten Sie, dass es eine Where-Methode gibt, die einfach eine neue MyClass zurückgibt, deren stringprop auf Hello World gesetzt ist. Zur Demonstration:

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);

Das Ergebnis ist die Ausgabe von "Hello World". Auch dieses Beispiel ist offensichtlich sinnlos, aber es beweist, dass die "where"-Syntax nur nach einer Where-Methode in Ihrem Code sucht, die eine Func.

2voto

Sander Punkte 24565

Abfrageausdrücke und Erweiterungsmethoden sind zwei Möglichkeiten, genau das Gleiche zu tun. Abfrageausdrücke werden beim Kompilieren in Erweiterungsmethoden umgewandelt - sie sind nur syntaktischer Zucker für Leute, die mit SQL besser vertraut sind.

Wenn Sie das schreiben:

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

Der Compiler wandelt dies um in:

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

Ich denke, dass Abfrageausdrücke nur aus Marketinggründen geschaffen wurden - ein SQL-ähnliches Sprachkonstrukt, das bei der Entwicklung von LINQ als Blickfang dienen sollte, und nicht etwas, das tatsächlich viel Nutzen bietet. Ich finde, dass die meisten Leute einfach die Erweiterungsmethoden direkt verwenden, da sie zu einem einheitlicheren Kodierungsstil führen, anstatt zu einer Mischung aus C# und SQL.

1voto

Tim Jarvis Punkte 17605

1./ Der Titel Ihrer Frage entspricht nicht dem, was Sie gefragt haben.
2./ Der Titel Ihrer Frage macht nicht wirklich Sinn. Linq steht für Language Integrated Query und ist ein Oberbegriff für eine Reihe von Technologien und Praktiken, IQueryable ist eine Schnittstelle, die üblicherweise verwendet wird, um Linq zu erleichtern.
3./ Zu Ihrer eigentlichen Frage: Der Hauptunterschied ist der Stil. Bei komplexen Abfragen wie dieser bevorzuge ich persönlich die zweite Version, da sie die Entwicklung der Ergebnismengen deutlich zeigt.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X