Condividi tramite


Traduzione dell'operatore di query standard

LINQ to SQL converte gli operatori di query standard in comandi SQL. Il processore di query del database determina la semantica di esecuzione della traduzione SQL.

Gli operatori di query standard vengono definiti in base alle sequenze. Una sequenza viene ordinata e si basa sull'identità di riferimento per ogni elemento della sequenza. Per altre informazioni, vedere Panoramica degli operatori di query standard (C#) o Panoramica degli operatori di query standard (Visual Basic).

SQL gestisce principalmente set di valori non ordinati. L'ordinamento è in genere un'operazione di post-elaborazione specificata in modo esplicito che viene applicata al risultato finale di una query anziché ai risultati intermedi. L'identità è definita dai valori. Per questo motivo, le query SQL vengono comprese per gestire multinsiemi (bags) anziché set.

I paragrafi seguenti descrivono le differenze tra gli operatori di query standard e la relativa conversione SQL per il provider SQL Server per LINQ to SQL.

Supporto dell'operatore

Concat

Il Concat metodo viene definito per i multiset ordinati in cui l'ordine del ricevitore e l'ordine dell'argomento sono gli stessi. Concat funziona come UNION ALL nei multiset seguiti dall'ordine comune.

Il passaggio finale consiste nell'ordinare in SQL prima che vengano prodotti i risultati. Concat non mantiene l'ordine degli argomenti. Per garantire l'ordinamento appropriato, è necessario ordinare in modo esplicito i risultati di Concat.

Intersezione, Eccetto, Unione

Le metodologie Intersect e Except sono ben definite solo sugli insiemi. La semantica per i multiset non è definita.

Il Union metodo viene definito per i multiset come concatenazione non ordinata dei multiset (in effetti il risultato della clausola UNION ALL in SQL).

Prendi, Salta

Take e Skip metodi sono ben definiti solo con set ordinati. La semantica per set non ordinati o multiset non è definita.

Annotazioni

Take e Skip presentano alcune limitazioni quando vengono usate nelle query su SQL Server 2000. Per altre informazioni, vedere la voce "Skip and Take Exceptions in SQL Server 2000" (Ignora e accetta eccezioni 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 questi metodi al 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

Il codice SQL generato sposta l'ordinamento alla fine, come indicato di seguito:

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]

Diventa evidente che tutti gli ordini specificati devono essere coerenti quando Take e Skip vengono concatenati. In caso contrario, i risultati non sono definiti.

Sia Take che Skip sono ben definiti per argomenti integrali costanti non negativi secondo la specifica degli operatori standard di interrogazione.

Operatori senza traduzione

I metodi seguenti non vengono convertiti da LINQ to SQL. Il motivo più comune è la differenza tra più set non ordinati e sequenze.

Operatori Motivazione
TakeWhile, SkipWhile Le query SQL operano su più set, non su sequenze. ORDER BY deve essere l'ultima clausola applicata ai risultati. Per questo motivo, non esiste alcuna traduzione per utilizzo generico per questi due metodi.
Reverse La traduzione di questo metodo è possibile per un set ordinato ma non è attualmente tradotta da LINQ to SQL.
Last, LastOrDefault La traduzione di questi metodi è possibile per un set ordinato ma non è attualmente tradotta da LINQ to SQL.
ElementAt, ElementAtOrDefault Le query SQL operano su più set, non su sequenze indicizzabili.
DefaultIfEmpty (overload con arg predefinito) In generale, non è possibile specificare un valore predefinito per una tupla arbitraria. I valori NULL per le tuple sono possibili in alcuni casi tramite gli outer join.

Traduzione di espressioni

Nessuna semantica

LINQ to SQL non impone la semantica di confronto di valori null in SQL. Gli operatori di confronto vengono convertiti sintatticamente nei rispettivi equivalenti SQL. Per questo motivo, la semantica riflette la semantica SQL definita dalle impostazioni di connessione o server. Ad esempio, due valori Null sono considerati diversi nelle impostazioni predefinite di SQL Server, ma è possibile modificare le impostazioni per modificare la semantica. LINQ to SQL non considera le impostazioni del server quando converte le query.

Un confronto con il valore letterale Null viene convertito nella versione SQL appropriata (is null o is not null).

Il valore di null nel confronto è definito da SQL Server. LINQ to SQL non modifica le regole di confronto.

Aggregazioni

Il metodo di aggregazione dell'Operatore Query Standard restituisce zero per una sequenza vuota o per una sequenza che contiene 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 si applicano alle aggregazioni in LINQ to SQL. Il Sum delle quantità di interi a 32 bit non viene calcolato con risultati a 64 bit. L'overflow può verificarsi per una conversione LINQ to SQL di Sum, anche se l'implementazione dell'operatore di query standard non causa un overflow per la sequenza in memoria corrispondente.

Analogamente, la traduzione dei valori interi di LINQ to SQL di Average viene calcolata come un integer, non come un double.

Argomenti entità

LINQ to SQL consente ai tipi di entità di essere utilizzati nei metodi GroupBy e OrderBy. Nella conversione di questi operatori, l'uso di un argomento di un tipo è considerato equivalente a specificare tutti i membri di tale 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 equivalenti/confrontabili

L'uguaglianza degli argomenti è necessaria nell'implementazione dei metodi seguenti:

LINQ to SQL supporta l'uguaglianza e il confronto per gli argomenti flat , ma non per gli argomenti che sono o contengono sequenze. Un argomento flat è un tipo di cui è possibile eseguire il mapping a una riga SQL. Una proiezione di uno o più tipi di entità determinati staticamente che non contengono una sequenza viene considerata un argomento piatto.

Di seguito sono riportati esempi di argomenti flat:

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

Di seguito sono riportati esempi di argomenti non flat (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 di Visual Basic

Le funzioni helper seguenti usate dal compilatore Visual Basic vengono convertite in operatori e funzioni SQL corrispondenti:

  • 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à

Restrizioni relative al mapping di ereditarietà

Per altre informazioni, vedere Procedura: Eseguire il mapping delle gerarchie di ereditarietà.

Ereditarietà nelle query

I cast C# sono supportati solo in fase di proiezione. I cast usati altrove non vengono tradotti e vengono ignorati. Oltre ai nomi delle funzioni SQL, SQL esegue in realtà solo l'equivalente di Common Language Runtime (CLR). Convert Ovvero, SQL può modificare il valore di un tipo in un altro. Non esiste alcun equivalente del cast CLR perché non esiste alcun concetto di reinterpretazione degli stessi bit come appartenenti a un altro tipo. Ecco perché un cast C# funziona solo in locale. Non è remoto.

Gli operatori is e as e il metodo GetType non sono limitati all'operatore Select. Possono essere usati anche in altri operatori di query.

Supporto di SQL Server 2008

A partire da .NET Framework 3.5 SP1, LINQ to SQL supporta il mapping ai nuovi tipi di data e ora introdotti con SQL Server 2008. Esistono tuttavia alcune limitazioni per gli operatori di query LINQ to SQL che è possibile usare quando si opera su valori mappati a questi nuovi tipi.

Operatori di query non supportati

Gli operatori di query seguenti non sono supportati sui valori mappati ai nuovi tipi di data e ora di SQL Server: DATETIME2, DATE, TIMEe DATETIMEOFFSET.

  • Aggregate

  • Average

  • LastOrDefault

  • OfType

  • Sum

Per ulteriori informazioni sul mapping a questi tipi di data e ora di SQL Server, consultare mappatura dei tipiSQL-CLR.

Supporto di SQL Server 2005

LINQ to SQL non supporta le funzionalità di SQL Server 2005 seguenti:

  • Procedure memorizzate scritte per SQL CLR.

  • 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 riscritture per sostituirle con join appropriati.

Cross Apply e Outer Apply vengono generati per gli spostamenti tra relazioni. Il set di query per cui tali riscritture sono possibili non è ben definito. Per questo motivo, il set minimo di query supportato per SQL Server 2000 è il set che non comporta lo spostamento tra relazioni.

testo/ntext

I tipi di dati text / ntext non possono essere usati in determinate operazioni di query su varchar(max) / nvarchar(max), supportate da Microsoft SQL Server 2005.

Per questa limitazione non è disponibile alcuna risoluzione. In particolare, non è possibile utilizzare Distinct() su alcun risultato contenente membri mappati su colonne text o ntext.

Comportamento attivato da query nidificate

Il componente di collegamento di SQL Server 2000 (tramite SP4) presenta alcune idiosincrasie che vengono attivate da query annidate. Il set di query SQL che attiva queste idioincrone non è ben definito. Per questo motivo, non è possibile definire il set di query LINQ to SQL che potrebbero causare eccezioni di SQL Server.

Operatori Skip e Take

Take e Skip presentano alcune limitazioni quando vengono usate nelle query su SQL Server 2000. Per altre informazioni, vedere la voce "Skip and Take Exceptions in SQL Server 2000" (Ignora e accetta eccezioni in SQL Server 2000) in Risoluzione dei problemi.

Materializzazione degli oggetti

La materializzazione crea oggetti CLR da righe restituite da una o più query SQL.

  • Le chiamate seguenti vengono eseguite localmente come parte della materializzazione:

    • Costruttori

    • ToString metodi nelle proiezioni

    • Cast di tipi nelle proiezioni

  • I metodi che seguono il AsEnumerable metodo vengono eseguiti localmente. Questo metodo non causa l'esecuzione immediata.

  • È possibile usare un oggetto struct come tipo restituito di un risultato della query o come membro del tipo di risultato. Le classi devono essere entità. I tipi anonimi vengono materializzati come istanze di classe, ma le strutture denominate (che non sono entità) possono essere usate nella proiezione.

  • Un membro del tipo di ritorno del risultato di una query può essere di tipo IQueryable<T>. Viene materializzata come raccolta locale.

  • I metodi seguenti determinano la materializzazione immediata della sequenza a cui vengono applicati i metodi:

Vedere anche