Conversione dell'operatore query standard
Gli operatori di query standard vengono convertiti in comandi SQL in LINQ to SQL. Il sistema di elaborazione delle query del database determina la semantica di esecuzione della conversione SQL.
Gli operatori di query standard vengono definiti in relazione alle sequenze. Una sequenza viene ordinata e si basa sull'identità del riferimento di ogni elemento della sequenza. Per altre informazioni, vedere Panoramica degli operatori di query standard (C#) o Panoramica degli operatori di query standard (Visual Basic).
In SQL vengono principalmente gestiti set non ordinati di valori. L'ordinamento è in genere un'operazione di post-elaborazione specificata in modo esplicito, che viene applicata al risultato finale di una query piuttosto che ai risultati intermedi. L'identità viene definita dai valori. Per questo motivo si presuppone che nelle query SQL vengano gestiti multiset, ovvero contenitori, anziché set.
Nei paragrafi seguenti vengono descritte le differenze tra gli operatori di query standard e la relativa conversione SQL per il provider SQL Server per LINQ to SQL.
Supporto degli operatori
Concat
Il metodo Concat viene definito per multiset ordinati in cui l'ordine del ricevente e l'ordine dell'argomento sono uguali. Il funzionamento di Concat sui multiset seguiti dall'ordine comune è analogo a quello di UNION ALL
.
Il passaggio finale in SQL consiste nell'ordinamento prima che vengano generati i risultati. Concat non mantiene l'ordine degli argomenti. Per assicurare che l'ordine sia appropriato, è necessario ordinare i risultati di Concat in modo esplicito.
Metodi Intersect, Except, Union
I metodi Intersect e Except sono definiti correttamente solo sui set, mentre la semantica per i tipi multiset non è definita.
Il metodo Union viene definito per i tipi multiset come concatenazione non ordinata di multiset, che corrisponde in effetti al risultato della clausola UNION ALL in SQL.
Metodi Take, Skip
I metodi Take e Skip sono definiti correttamente solo sui set ordinati. mentre la semantica per i set non ordinati o i tipi multiset non è definita.
Nota
Take e Skip presentano alcune limitazioni quando vengono usati nelle query su SQL Server 2000. Per altre informazioni, vedere la voce relativa alle eccezioni di Skip e Take in SQL Server 2000 in Risoluzione dei problemi.
A causa delle limitazioni relative all'ordinamento in SQL, LINQ to SQL tenta di spostare l'ordinamento dell'argomento di tali metodi nel risultato del metodo. Si consideri ad esempio la query LINQ to SQL seguente:
var custQuery =
(from cust in db.Customers
where cust.City == "London"
orderby cust.CustomerID
select cust).Skip(1).Take(1);
Dim custQuery = _
From cust In db.Customers _
Where cust.City = "London" _
Order By cust.CustomerID _
Select cust Skip 1 Take 1
L'SQL generato per questo codice sposta l'ordinamento alla fine, come segue:
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]
È quindi evidente che quando Take e Skip vengono concatenati, tutto l'ordinamento specificato deve essere coerente. In caso contrario i risultati non saranno definiti.
Sia Take che Skip sono definiti correttamente per gli argomenti di tipo integrale costante non negativi basati sulla specifica dell'operatore di query standard.
Operatori senza conversione
I metodi seguenti non vengono convertiti da LINQ to SQL. Il motivo più comune è la differenza tra i multiset non ordinati e le sequenze.
Operatori | Spiegazione |
---|---|
TakeWhile, SkipWhile | Le query SQL vengono eseguite su multiset, non su sequenze. ORDER BY deve essere l'ultima clausola applicata ai risultati. Per questo motivo non esiste una conversione di tipo generico per questi due metodi. |
Reverse | La conversione di questo metodo è possibile per un set ordinato, ma attualmente non viene eseguita da LINQ to SQL. |
Last, LastOrDefault | La conversione di questi metodi è possibile per un set ordinato, ma attualmente non viene eseguita da LINQ to SQL. |
ElementAt, ElementAtOrDefault | Le query SQL vengono eseguite su multiset, non sulle sequenze indicizzabili. |
DefaultIfEmpty (overload con argomento predefinito) | In generale non è possibile specificare un valore predefinito per una tupla arbitraria. In alcuni casi i valori null per le tuple sono consentiti tramite outer join. |
Conversione di espressione
Semantica Null
LINQ to SQL non impone la semantica di confronto in SQL. Gli operatori di confronto vengono sintatticamente convertiti negli equivalenti SQL. Per questo motivo la semantica riflette la semantica SQL definita nelle impostazioni di connessione o del server. Ad esempio, due valori null sono considerati non uguali nelle impostazioni predefinite di SQL Server, ma è possibile modificare tali impostazioni per modificare la semantica. In LINQ to SQL non vengono considerate le impostazioni del server durante la conversione delle query.
Un confronto con il valore letterale null viene convertito nella versione SQL appropriata (is null
o is not null
).
Il valore null
nelle regole di confronto viene definito da SQL Server. LINQ to SQL non modifica le regole di confronto.
Aggregazioni
Il metodo di aggregazione dell'operatore di query standard Sum restituisce valori zero per tutte le sequenze vuote o che contengono solo valori null. In LINQ to SQL la semantica di SQL viene lasciata invariata e Sum restituisce null
invece di zero per una sequenza vuota o per una sequenza che contiene solo valori Null.
Le limitazioni di SQL sui risultati intermedi vengono applicate agli aggregati in LINQ to SQL. La somma, Sum, delle quantità di valori integer a 32 bit non viene calcolata utilizzando risultati a 64 bit È possibile che si verifichi un overflow per una conversione LINQ to SQL di Sum, anche se l'implementazione dell'operatore di query standard non provoca un overflow per la corrispondente sequenza in memoria.
In modo analogo la conversione LINQ to SQL di Average di valori integer viene calcolata come un valore integer
, non come un valore double
.
Argomenti di entità
LINQ to SQL consente l'uso di tipi di entità nei metodi GroupBy e OrderBy. Nella conversione di tali operatori l'uso di un argomento di un tipo viene considerato equivalente della specifica di tutti i membri di quel tipo. Ad esempio, il codice seguente è equivalente.
db.Customers.GroupBy(c => c);
db.Customers.GroupBy(c => new { c.CustomerID, c.ContactName });
db.Customers.GroupBy(Function(c) c)
db.Customers.GroupBy(Function(c) New With {c.CustomerID, _
c.ContactName})
Argomenti di uguaglianza/confronto
Nell'implementazione dei metodi elencati di seguito è richiesta l'uguaglianza di argomenti:
LINQ to SQL supporta uguaglianza e confronto per gli argomenti non strutturati, ma non per gli argomenti corrispondenti a sequenze o che le contengono. Un argomento non strutturato è un tipo di cui è possibile eseguire il mapping a una riga SQL. Una proiezione di uno o più tipi di entità, per cui è possibile determinare staticamente che non è presente una sequenza, viene considerata un argomento non strutturato.
Di seguito sono riportati esempi di argomenti non strutturati:
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 });
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})
Gli esempi seguenti si riferiscono ad argomenti strutturati (gerarchici):
// 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);
' 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)
Conversione di funzioni Visual Basic
Le seguenti funzioni di supporto usate dal compilatore Visual Basic vengono convertite nei corrispondenti operatori e funzioni SQL:
CompareString
DateTime.Compare
Decimal.Compare
IIf (in Microsoft.VisualBasic.Interaction)
Metodi di conversione:
ToBoolean
ToSByte
ToByte
ToChar
ToCharArrayRankOne
ToDate
ToDecimal
ToDouble
ToInteger
ToUInteger
ToLong
ToULong
ToShort
ToUShort
ToSingle
ToString
Supporto dell'ereditarietà
Limitazioni relative al mapping di ereditarietà
Per altre informazioni, vedere Procedura: Eseguire il mapping di gerarchie di ereditarietà.
Ereditarietà nelle query
I cast C# sono supportati solo nella proiezione. I cast usati in altri contesti non vengono convertiti e sono ignorati. A parte i nomi delle funzioni SQL, in SQL viene in effetti eseguito solo l'equivalente dell'operazione Convert di Common Language Runtime (CLR). In altre parole SQL è in grado di modificare il valore di un tipo in un altro. Non è disponibile un cast CLR equivalente, in quanto non esiste un concetto che consenta di reinterpretare gli stessi bit di un altro tipo. Per questo motivo un cast C# funziona solo localmente e non viene usato in modalità remota.
Gli operatori is
e as
e il metodo GetType
non sono limitati all'operatore Select
, pertanto possono essere usati anche in altri operatori di query.
Supporto di SQL Server 2008
A partire da .NET Framework versione 3.5 SP1, LINQ to SQL supporta il mapping ai nuovi tipi di data e ora introdotti con SQL Server 2008. Vi sono tuttavia alcune limitazioni relative agli operatori di query LINQ to SQL che è possibile usare quando si lavora con valori mappati a questi nuovi tipi.
Operatori di query non supportati
Gli operatori di query seguenti non sono supportati per i valori mappati ai nuovi tipi di data e ora SQL Server: DATETIME2
, DATE
, TIME
e DATETIMEOFFSET
.
Aggregate
Average
LastOrDefault
OfType
Sum
Per altre informazioni sul mapping a questi tipi di data e ora di SQL Server, vedere Mapping dei tipi SQL-CLR.
Supporto di SQL Server 2005
LINQ to SQL non supporta le seguenti funzionalità di SQL Server 2005:
Stored procedure scritte per CLR SQL.
Tipo definito dall'utente.
Funzionalità di query XML.
Supporto di SQL Server 2000
Le limitazioni seguenti di SQL Server 2000 (rispetto a Microsoft SQL Server 2005) influiscono sul supporto LINQ to SQL.
Operatori Cross Apply e Outer Apply
Questi operatori non sono disponibili in SQL Server 2000. LINQ to SQL tenta una serie di operazioni di riscrittura per sostituirli con join appropriati.
Cross Apply
e Outer Apply
vengono generati per la navigazione tra relazioni. Il set di query per cui tali riscritture sono possibili non è esattamente definito. Per questo motivo il set minimo di query supportato per SQL Server 2000 è quello che non comporta la navigazione tra relazioni.
text/ntext
I tipi di text
/ ntext
dati non possono essere usati in determinate operazioni di query su varchar(max)
/ nvarchar(max)
, che sono supportate da Microsoft SQL Server 2005.
Non sono disponibili risoluzioni per questa limitazione. In particolare, non è possibile usare Distinct()
su qualsiasi risultato contenente membri di cui è stato eseguito il mapping a colonne text
o ntext
.
Comportamento attivato dalle query annidate
Il gestore di associazione di SQL Server 2000, fino alla versione SP4, presenta alcune peculiarità attivate dalle query annidate. Il set di query SQL che attiva queste peculiarità non è esattamente definito. Per questo motivo non è possibile definire il set di query LINQ to SQL che potrebbero provocare eccezioni di SQL Server.
Operatori Skip e Take
Take e Skip presentano alcune limitazioni quando vengono usati nelle query su SQL Server 2000. Per altre informazioni, vedere la voce relativa alle eccezioni di Skip e Take in SQL Server 2000 in Risoluzione dei problemi.
Materializzazione di oggetti
La materializzazione crea oggetti CLR da righe restituite da una o più query SQL.
Le chiamate seguenti vengono eseguite localmente nell'ambito dell'operazione di materializzazione:
Costruttori
Metodi
ToString
nelle proiezioniCast dei tipi nelle proiezioni
I metodi che seguono il metodo AsEnumerable vengono eseguiti localmente. Questo metodo non provoca l'esecuzione immediata.
È possibile usare
struct
come tipo restituito del risultato di una query o come un membro del tipo di risultato. Le entità devono essere classi. I tipi anonimi vengono materializzati come istanze della classe, tuttavia gli struct denominati, non le entità, possono essere usati nella proiezione.Un membro del tipo restituito del risultato di una query può essere di tipo IQueryable<T> e viene materializzato come una raccolta locale.
I metodi seguenti provocano la materializzazione immediata della sequenza a cui vengono applicati: