Übersetzen von Standardabfrageoperatoren (LINQ to SQL)
Aktualisiert: November 2007
LINQ to SQL übersetzt Standardabfrageoperatoren in SQL-Befehle. Der Abfrageprozessor der Datenbank bestimmt die Ausführungssemantik der SQL-Übersetzung.
Standardabfrageoperatoren werden mithilfe von Sequenzen definiert. Eine Sequenz wird sortiert und basiert auf der Verweisidentität für jedes Element der Sequenz. Weitere Informationen finden Sie unter Übersicht über Standardabfrageoperatoren.
SQL beschäftigt sich hauptsächlich mit ungeordneten Sätzen von Werten. Die Sortierung ist in der Regel ein explizit angegebener, nachgelagerter Prozess, der auf das Endergebnis einer Abfrage und nicht auf Zwischenergebnisse angewendet wird. Die Identität wird durch Werte definiert. Aus diesem Grund befassen sich SQL-Abfragen mit Multisets (Sammlungen) und nicht mit Sätzen.
Die folgenden Abschnitte beschreiben die Unterschiede zwischen den Standardabfrageoperatoren und ihrer SQL-Übersetzung für den SQL Server-Anbieter in LINQ to SQL.
Operatorunterstützung
Concat
Die Concat<TSource>-Methode ist für sortierte Multisets definiert, bei denen die Reihenfolge des Empfängers und des Arguments identisch ist. Concat<TSource> fungiert als UNION ALL für die Multisets, gefolgt von der Befehlsreihenfolge.
Der letzte Schritt besteht in der SQL-Sortierung, bevor die Ergebnisse erzeugt werden. Concat<TSource> behält die Argumentreihenfolge nicht bei. Um die entsprechende Sortierung sicherzustellen, müssen Sie die Ergebnisse von Concat<TSource> explizit sortieren.
Intersect, Except, Union
Die Intersect-Methode und die Except-Methode sind nur für Sätze gut definiert. Die Semantik für Multisets ist nicht definiert.
Die Union-Methode ist für Multisets definiert, und zwar als unsortierte Verkettung der Multisets (effektiv als Ergebnis der UNION ALL-Klausel in SQL).
Take, Skip
Die Take<TSource>-Methode und die Skip<TSource>-Methode sind nur für sortierte Sätze gut definiert. Die Semantik für ungeordnete Sätze oder Multisets ist nicht definiert.
Hinweis: |
---|
Take<TSource> und Skip<TSource> weisen bestimmte Einschränkungen auf, wenn diese in Abfragen mit SQL Server 2000 verwendet werden. Weitere Informationen finden Sie im Eintrag "Überspringen und Behandeln von Ausnahmen in SQL Server 2000" unter Problembehandlung (LINQ to SQL). |
Aufgrund der eingeschränkten Sortierung in SQL versucht LINQ to SQL, die Sortierung der Methodenargumente auf das Methodenergebnis zu verlagern. Betrachten Sie z. B. die folgende LINQ to SQL-Abfrage:
Dim custQuery = _
From cust In db.Customers _
Where cust.City = "London" _
Order By cust.CustomerID _
Select cust Skip 1 Take 1
var custQuery =
(from cust in db.Customers
where cust.City == "London"
orderby cust.CustomerID
select cust).Skip(1).Take(1);
Das generierte SQL für diesen Code verschiebt die Sortierung wie folgt ans Ende:
SELECT TOP 1 [t0].[CustomerID], [t0].[CompanyName],
FROM [Customers] AS [t0]
WHERE (NOT (EXISTS(
SELECT NULL AS [EMPTY]
FROM (
SELECT TOP 1 [t1].[CustomerID]
FROM [Customers] AS [t1]
WHERE [t1].[City] = @p0
ORDER BY [t1].[CustomerID]
) AS [t2]
WHERE [t0].[CustomerID] = [t2].[CustomerID]
))) AND ([t0].[City] = @p1)
ORDER BY [t0].[CustomerID]
Es ist offensichtlich, dass die angegebene Sortierung konsistent sein muss, wenn Take<TSource> und Skip<TSource> verkettet werden. Andernfalls sind die Ergebnisse nicht definiert.
Take<TSource> und Skip<TSource> sind für nicht negative, konstante Integralargumente auf der Basis der Spezifikation für Standardabfrageoperatoren gut definiert.
Operatoren ohne Übersetzung
Die folgenden Methoden werden nicht von LINQ to SQL übersetzt. Der einfachste Grund ist der Unterschied zwischen ungeordneten Multisets und Sequenzen.
Operatoren |
Begründung |
---|---|
SQL-Abfragen verwenden Multisets, keine Sequenzen. ORDER BY muss die letzte Klausel sein, die auf die Ergebnisse angewendet wird. Aus diesem Grund gibt es keine allgemeine Übersetzung dieser beiden Methoden. |
|
Die Übersetzung dieser Methode ist für eine geordnete Menge möglich. Sie wird jedoch derzeit von LINQ to SQL nicht übersetzt. |
|
Die Übersetzung dieser Methoden ist für eine geordnete Menge möglich. Sie werden jedoch derzeit von LINQ to SQL nicht übersetzt. |
|
SQL-Abfragen verwenden Multisets, keine indizierbaren Sequenzen. |
|
DefaultIfEmpty (Überladung mit Standard-arg) |
Im Allgemeinen kann ein Standardwert nicht für ein beliebiges Tupel angegeben werden. NULL-Werte für Tupel sind in einigen Fällen durch äußere Verknüpfungen möglich. |
Ausdrucksübersetzung
NULL-Semantik
LINQ to SQL wendet keine NULL-Vergleichssemantik auf SQL an. Vergleichsoperatoren werden syntaktisch zu ihren SQL-Entsprechungen übersetzt. Aus diesem Grund reflektiert die Semantik SQL-Semantik, die von Server- oder Verbindungseinstellungen definiert wird. Zwei NULL-Werte gelten beispielsweise bei den standardmäßigen SQL Server-Einstellungen als ungleich. Sie können jedoch die Einstellungen ändern, um die Semantik anzupassen. LINQ to SQL berücksichtigt bei der Übersetzung von Abfragen keine Servereinstellungen.
Ein Vergleich mit dem NULL-Literal wird in die entsprechende SQL-Version (is null oder is not null) übersetzt.
Der Wert null in der Zusammenstellung wird durch SQL Server definiert. LINQ to SQL ändert die Zusammenstellung nicht.
Aggregate
Die Aggregationsmethode für Standardabfrageoperatoren Sum ergibt bei einer leeren Sequenz oder bei einer aus Nullen bestehenden Sequenz 0. In LINQ to SQL bleibt die Semantik von SQL unverändert, und Sum ergibt bei einer leeren oder aus Nullen bestehenden Sequenz null an Stelle von 0.
SQL-Einschränkungen für Zwischenergebnisse gelten in LINQ to SQL für Summen. Die Sum von 32-Bit-Ganzzahlmengen wird nicht berechnet, indem man 64-Bit-Ergebnisse verwendet. Bei einer LINQ to SQL-Übersetzung von Sum kann es zu einem Überlauf kommen, auch wenn die Implementierung von Standardabfrageoperatoren bei der entsprechenden Sequenz im Arbeitsspeicher keinen Überlauf verursacht.
In gleicher Weise wird die LINQ to SQL-Übersetzung von Average zu Ganzzahlen als integer und nicht als double übersetzt.
Entitätsargumente
LINQ to SQL aktiviert Entitätstypen zur Verwendung in der GroupBy-Methode und in der OrderBy-Methode. In der Übersetzung dieser Operatoren gilt die Verwendung eines Arguments als Entsprechung zur Angabe aller Member dieses Typs. Der folgende Code ist z. B. äquivalent:
db.Customers.GroupBy(Function(c) c)
db.Customers.GroupBy(Function(c) New With {c.CustomerID, _
c.ContactName})
db.Customers.GroupBy(c => c);
db.Customers.GroupBy(c => new { c.CustomerID, c.ContactName });
Gleichwertige/vergleichbare Argumente
Die Gleichheit von Argumenten ist in der Implementierung der folgenden Methoden erforderlich:
LINQ to SQL unterstützt Gleichheit und Vergleich für flache Argumente, aber nicht für Argumente, die Sequenzen sind oder enthalten. Ein flaches Argument ist ein Typ, der einer SQL-Zeile zugeordnet werden kann. Eine Projektion von einem oder mehreren statisch festgelegten Entitätstypen ohne Sequenz gilt als flaches Argument.
Es folgen Beispiele für flache Argumente:
db.Customers.Select(Function(c) c)
db.Customers.Select(Function(c) New With {c.CustomerID, c.City})
db.Orders.Select(Function(o) New With {o.OrderID, o.Customer.City})
db.Orders.Select(Function(o) New With {o.OrderID, o.Customer})
db.Customers.Select(c => c);
db.Customers.Select(c => new { c.CustomerID, c.City });
db.Orders.Select(o => new { o.OrderID, o.Customer.City });
db.Orders.Select(o => new { o.OrderID, o.Customer });
Es folgen Beispiele für nicht flache (hierarchische) Argumente.
' In the following line, c.Orders is a sequence.
db.Customers.Select(Function(c) New With {c.CustomerID, c.Orders})
' In the following line, the result has a sequence.
db.Customers.GroupBy(Function(c) c.City)
// In the following line, c.Orders is a sequence.
db.Customers.Select(c => new { c.CustomerID, c.Orders });
// In the following line, the result has a sequence.
db.Customers.GroupBy(c => c.City);
Visual Basic-Funktionsübersetzung
Die folgenden, vom Visual Basic-Compiler verwendeten Hilfsfunktionen werden in entsprechende SQL-Operatoren und -Funktionen übersetzt:
CompareString
DateTime.Compare
Decimal.Compare
IIf (in Microsoft.VisualBasic.Interaction)
Konvertierungsmethoden:
ToBoolean |
ToSByte |
ToByte |
ToChar |
ToCharArrayRankOne |
ToDate |
ToDecimal |
ToDouble |
ToInteger |
ToUInteger |
ToLong |
ToULong |
ToShort |
ToUShort |
ToSingle |
ToString |
Vererbungsunterstützung
Einschränkungen der Vererbungszuordnung
Weitere Informationen finden Sie unter Gewusst wie: Zuordnen von Vererbungshierarchien (LINQ to SQL).
Vererbung in Abfragen
C#-Umwandlungen werden nur in Projektionen unterstützt. An anderer Stelle verwendete Umwandlungen werden nicht übersetzt, sonder ignoriert. Neben den SQL-Funktionsnamen führt SQL tatsächlich nur das Äquivalent von Common Language Runtime (CLR) Convert aus. Das heißt, SQL kann den Wert eines Typs ändern. Es gibt keine Entsprechung zu CLR-Umwandlungen, da es kein Konzept für die Neuinterpretation der gleichen Bits als die eines anderen Typs gibt. Aus diesem Grund funktioniert eine C#-Umwandlung nur lokal. Eine Remoteausführung ist nicht möglich.
Der is-Operator und der as-Operator sowie die GetType-Methode werden nicht auf den Select-Operator beschränkt. Sie können auch in anderen Abfrageoperatoren verwendet werden.
SQL Server 2008-Unterstützung
Ab .NET Framework 3.5 SP1 unterstützt LINQ to SQL das Mapping zu den in SQL Server 2008 neu eingeführten Datums- und Uhrzeittypen. Einschränkungen bestehen jedoch für die LINQ to SQL-Abfrageoperatoren, die beim Arbeiten mit den diesen neuen Typen zugeordneten Werten verwendet werden können.
Nicht unterstützte Abfrageoperatoren
Die folgenden Abfrageoperatoren werden nicht für Werte unterstützt, die den neuen Datums- und Uhrzeittypen von SQL Server zugeordnet sind: DATETIME2, DATE, TIME und DATETIMEOFFSET.
Aggregate
Average
LastOrDefault
OfType
Sum
Weitere Informationen über das Mapping zu diesen Datums- und Uhrzeittypen von SQL Server finden Sie unter SQL CLR-Typzuordnung (LINQ to SQL).
SQL Server 2005-Unterstützung
LINQ to SQL bietet keine Unterstützung für die folgenden SQL Server 2005-Features:
Gespeicherte Prozeduren für SQL CLR.
Benutzerdefinierter Typ.
XML-Abfragefeatures.
SQL Server 2000-Unterstützung
Die folgenden SQL Server 2000-Einschränkungen (im Vergleich zu Microsoft SQL Server 2005) betreffen die LINQ to SQL-Unterstützung.
Cross Apply-Operator und Outer Apply-Operator
Diese Operatoren stehen in SQL Server 2000 nicht zur Verfügung. LINQ to SQL versucht eine Reihe von erneuten Schreibzugriffen, um diese durch angemessene Verknüpfungen zu ersetzen.
Cross Apply und Outer Apply werden für Beziehungsnavigation erzeugt. Der Satz von Abfragen, für den solche erneuten Schreibzugriffe möglich sind, ist nicht klar definiert. Aus diesem Grund umfasst der minimale für SQL Server 2000 unterstützte Abfragesatz jene Elemente, die keine Beziehungsnavigation beinhalten.
text / ntext
Die Datentypen text / ntext können in bestimmten Abfrageoperationen für varchar(max) / nvarchar(max), die von Microsoft SQL Server 2005 unterstützt werden, nicht verwendet werden.
Für diese Einschränkung ist keine Lösung verfügbar. Sie können insbesondere Distinct() nicht für Ergebnisse verwenden, die Member enthalten, die der text-Spalte oder der ntext-Spalte zugeordnet sind.
Von verschachtelten Abfragen ausgelöstes Verhalten
Die SQL Server 2000-Bindung (durch SP4) weist einige Eigenheiten auf, die von verschachtelten Abfragen ausgelöst werden. Der Satz von SQL-Abfragen, der diese Eigenheiten auslöst, ist nicht klar definiert. Aus diesem Grund können Sie den Satz von LINQ to SQL-Abfragen, der zu SQL Server-Ausnahmen führen kann, nicht definieren.
Skip-Operator und Take-Operator
Take<TSource> und Skip<TSource> weisen bestimmte Einschränkungen hinsichtlich der Verwendung in Abfragen mit SQL Server 2000 auf. Weitere Informationen finden Sie im Eintrag "Überspringen und Behandeln von Ausnahmen in SQL Server 2000" unter Problembehandlung (LINQ to SQL).
Materialisieren von Objekten
Die Materialisierung erstellt CLR-Objekte aus Zeilen, die von einer oder mehreren SQL-Abfragen zurückgegeben werden.
Die folgenden Aufrufe werden als Teil der Materialisierung lokal ausgeführt:
Konstruktoren
ToString-Methoden in Projektionen
Typumwandlungen in Projektionen
Methoden, die der AsEnumerable<TSource>-Methode folgen, werden lokal ausgeführt. Diese Methode verursacht keine unmittelbare Ausführung.
Sie können einen struct als Rückgabetyp eines Abfrageergebnisses oder als Member des Ergebnistyps verwenden. Entitäten müssen Klassen sein. Anonyme Typen werden als Klasseninstanzen materialisiert. Benannte structs (Nicht-Entitäten) können jedoch in Projektionen verwendet werden.
Ein Member des Rückgabetyps eines Abfrageergebnisses kann vom Typ IQueryable<T> sein. Er wird als lokale Auflistung materialisiert.
Die folgenden Methoden verursachen die unmittelbare Materialisierung der Sequenz, auf die die Methoden angewendet werden:
Siehe auch
Aufgaben
Gewusst wie: Zurückgeben oder Überspringen von Elementen in einer Sequenz (LINQ to SQL)
Gewusst wie: Verketten von zwei Sequenzen (LINQ to SQL)
Gewusst wie: Zurückgeben der Satzdifferenz zwischen zwei Sequenzen (LINQ to SQL)
Gewusst wie: Zurückgeben der Schnittmenge von zwei Sequenzen (LINQ to SQL)
Gewusst wie: Zurückgeben der Vereinigungsmenge von zwei Sequenzen (LINQ to SQL)