Condividi tramite


Conversione dell'operatore di query standard (LINQ to SQL)

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 ulteriori informazioni, vedere Cenni preliminari sugli operatori di query standard.

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<TSource> viene definito per multiset ordinati in cui l'ordine del ricevente e l'ordine dell'argomento sono uguali. Il funzionamento di Concat<TSource> 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<TSource> non mantiene l'ordine degli argomenti. Per assicurare che l'ordine sia appropriato, è necessario ordinare i risultati di Concat<TSource> 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<TSource> e Skip<TSource> sono definiti correttamente solo sugli set ordinati, mentre la semantica per i set non ordinati o i tipi multiset non è definita.

NotaNota

Take<TSource> e Skip<TSource> presentano alcune limitazioni quando vengono utilizzati nelle query su SQL Server 2000.Per ulteriori informazioni, vedere la voce relativa alle eccezioni di Skip e Take in SQL Server 2000 in Risoluzione dei problemi (LINQ to SQL).

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 seguente query LINQ to SQL:

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

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<TSource> e Skip<TSource> vengono concatenati, tutto l'ordinamento specificato deve essere coerente. In caso contrario i risultati non saranno definiti.

Sia Take<TSource> che Skip<TSource> 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 logica:

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<TSource>

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<TSource>, ElementAtOrDefault<TSource>

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.

Aggregati

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 rimane invariata e Sum restituisce null anziché zero per le sequenze vuote o che contengono 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 ed è 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'utilizzo di tipi di entità nei metodi GroupBy e OrderBy. Nella conversione di tali operatori l'utilizzo 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(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 });

Argomenti di uguaglianza/confronto

Nell'implementazione dei metodi elencati di seguito è richiesta l'uguaglianza di argomenti:

Contains

Skip<TSource>

Union

Intersect

Except

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

Gli esempi seguenti si riferiscono ad argomenti strutturati (gerarchici).

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

Conversione di funzioni Visual Basic

Le seguenti funzioni di supporto utilizzate 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 ulteriori informazioni, vedere Procedura: mappare le gerarchie di ereditarietà (LINQ to SQL).

Ereditarietà nelle query

I cast C# sono supportati solo nella proiezione. I cast utilizzati 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 utilizzato in modalità remota.

Gli operatori is e as e il metodo GetType non sono limitati all'operatore Select, pertanto possono essere utilizzati 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 utilizzare 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 ulteriori informazioni sul mapping a questi tipi di data e ora SQL Server, vedere Mapping dei tipi CLR SQL (LINQ to SQL).

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 seguenti limitazioni di SQL Server 2000, rispetto a Microsoft SQL Server 2005, influiscono sul supporto di 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 dati text/ntext non possono essere utilizzati 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 utilizzare 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<TSource> e Skip<TSource> presentano determinate limitazioni quando vengono utilizzati nelle query su SQL Server 2000. Per ulteriori informazioni, vedere la voce relativa alle eccezioni di Skip e Take in SQL Server 2000 in Risoluzione dei problemi (LINQ to SQL).

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 proiezioni

    • Cast dei tipi nelle proiezioni

  • I metodi che seguono il metodo AsEnumerable<TSource> vengono eseguiti localmente. Questo metodo non provoca l'esecuzione immediata.

  • È possibile utilizzare 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 utilizzati 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:

Vedere anche

Attività

Procedura: restituire o ignorare gli elementi in una sequenza (LINQ to SQL)

Procedura: concatenare due sequenze (LINQ to SQL)

Procedura: restituire la differenza dei set tra due sequenze (LINQ to SQL)

Procedura: restituire l'intersezione dei set di due sequenze (LINQ to SQL)

Procedura: restituire l'unione di set di due sequenze (LINQ to SQL)

Altre risorse

Riferimento (LINQ to SQL)