Partilhar via


Tradução do operador de consulta padrão

LINQ to SQL traduz Operadores de Consulta Padrão para comandos SQL. O processador de consultas do banco de dados determina a semântica de execução da tradução SQL.

Os Operadores de Consulta Padrão são definidos em relação a sequências. Uma sequência é ordenada e depende da identidade de referência para cada elemento da sequência. Para obter mais informações, consulte Visão Geral dos Operadores de Consulta Padrão (C#) ou Visão Geral dos Operadores de Consulta Padrão (Visual Basic).

SQL lida principalmente com conjuntos não ordenados de valores. A ordenação é normalmente uma operação de pós-processamento explicitamente declarada que é aplicada ao resultado final de uma consulta e não aos resultados intermediários. A identidade é definida por valores. Por esse motivo, as consultas SQL são concebidas para lidar com multisets (bags) em vez de conjuntos.

Os parágrafos seguintes descrevem as diferenças entre os "Operadores de Consulta Padrão" e a sua tradução SQL para o provedor de SQL Server em LINQ to SQL.

Suporte ao Operador

Concat

O Concat método é definido para conjuntos ordenados onde a ordem do recetor e a ordem do argumento são as mesmas. Concat funciona como UNION ALL sobre os multisets seguidos pela ordem comum.

A etapa final é ordenar em SQL antes que os resultados sejam produzidos. Concat não preserva a ordem dos seus argumentos. Para garantir o pedido apropriado, você deve solicitar explicitamente os resultados do Concat.

Intersecção, Exceto, União

Os métodos Intersect e Except são bem definidos apenas em conjuntos. A semântica para multiconjuntos é indefinida.

O Union método é definido para multisets como a concatenação não ordenada dos multisets (efetivamente o resultado da cláusula UNION ALL em SQL).

Tomar, Ignorar

Take e Skip os métodos são bem definidos apenas contra conjuntos ordenados. A semântica para conjuntos não ordenados ou multiconjuntos são indefinidas.

Observação

Take e Skip têm certas limitações quando são usados em consultas no SQL Server 2000. Para obter mais informações, consulte a entrada "Ignorar e Obter Exceções no SQL Server 2000" em Solução de Problemas.

Devido a limitações na ordenação em SQL, LINQ to SQL tenta mover a ordenação do argumento desses métodos para o resultado do método. Por exemplo, considere a seguinte consulta LINQ to SQL:

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

O SQL gerado para esse código move a ordem para o final, da seguinte maneira:

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]

Torna-se óbvio que todas as ordens especificadas devem ser consistentes quando Take e Skip estão encadeadas. Caso contrário, os resultados são indefinidos.

Ambos Take e Skip são bem definidos para argumentos integrais constantes e não negativos com base na especificação do Operador de Consulta Padrão.

Operadores sem tradução

Os métodos a seguir não são traduzidos pelo LINQ para SQL. A razão mais comum é a diferença entre multiconjuntos não ordenados e sequências.

Operadores Fundamentação
TakeWhile, SkipWhile As consultas SQL operam em vários conjuntos, não em sequências. ORDER BY deve ser a última cláusula aplicada aos resultados. Por esta razão, não existe uma tradução de uso geral para estes dois métodos.
Reverse A tradução deste método é possível para um conjunto ordenado, mas atualmente não é traduzida pelo LINQ para SQL.
Last, LastOrDefault A tradução desses métodos é possível para um conjunto ordenado, mas atualmente não é traduzida pelo LINQ para SQL.
ElementAt, ElementAtOrDefault As consultas SQL operam em vários conjuntos, não em sequências indexáveis.
DefaultIfEmpty (sobrecarga com arg padrão) Em geral, um valor padrão não pode ser especificado para uma tupla arbitrária. Valores nulos para tuplas são possíveis em alguns casos através de junções externas.

Tradução de Expressões

Semântica Nula

LINQ to SQL não impõe semântica de comparação nula no SQL. Os operadores de comparação são traduzidos sintaticamente para seus equivalentes SQL. Por esse motivo, a semântica reflete a semântica SQL definida pelas configurações de servidor ou conexão. Por exemplo, dois valores nulos são considerados desiguais nas configurações padrão do SQL Server, mas você pode alterar as configurações para alterar a semântica. O LINQ to SQL não considera as configurações do servidor quando traduz consultas.

Uma comparação com o literal null é convertida para a versão SQL apropriada (is null ou is not null).

O valor de null no agrupamento é definido pelo SQL Server. LINQ to SQL não altera o agrupamento.

Agregados

O método Sum de agregação Standard Query Operator é avaliado como zero para uma sequência vazia ou para uma sequência que contém apenas nulos. No LINQ to SQL, a semântica do SQL é deixada inalterada e Sum é avaliada como null em vez de zero para uma sequência vazia ou para uma sequência que contém apenas nulos.

As limitações do SQL em resultados intermediários aplicam-se a agregações em LINQ to SQL. O Sum de quantidades inteiras de 32 bits não é calculado usando resultados de 64 bits. Pode ocorrer transbordo numa tradução LINQ to SQL de Sum, mesmo que a implementação do Operador de Consulta Padrão não cause um transbordo para a sequência correspondente na memória.

Da mesma forma, na tradução de LINQ para SQL dos valores inteiros de Average, calcula-se como um integer, não como um double.

Argumentos da entidade

O LINQ to SQL permite que tipos de entidade sejam usados nos métodos GroupBy e OrderBy. Na tradução desses operadores, o uso de um argumento de um tipo é considerado o equivalente a especificar todos os membros desse tipo. Por exemplo, o código a seguir é 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})

Argumentos Equatáveis / Comparáveis

A igualdade de argumentos é necessária na implementação dos seguintes métodos:

O LINQ to SQL oferece suporte à igualdade e à comparação para argumentos simples , mas não para argumentos que são ou contêm sequências. Um argumento simples é um tipo que pode ser mapeado para uma linha SQL. Uma projeção de um ou mais tipos de entidade que podem ser determinados estaticamente para não conter uma sequência é considerada um argumento simples.

Seguem-se exemplos de argumentos simples:

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

Seguem-se exemplos de argumentos não planos (hierárquicos):

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

Tradução de funções do Visual Basic

As seguintes funções auxiliares que são usadas pelo compilador do Visual Basic são convertidas para operadores e funções SQL correspondentes:

  • CompareString

  • DateTime.Compare

  • Decimal.Compare

  • IIf (in Microsoft.VisualBasic.Interaction)

Métodos de conversão:

  • ToBoolean
  • ToSByte
  • ToByte
  • ToChar
  • ToCharArrayRankOne
  • ToDate
  • ToDecimal
  • ToDouble
  • ToInteger
  • ToUInteger
  • ToLong
  • ToULong
  • ToShort
  • ToUShort
  • ToSingle
  • ToString

Suporte sucessório

Restrições ao mapeamento de herança

Para obter mais informações, consulte Como mapear hierarquias de herança.

Herança em consultas

As versões em C# são suportadas apenas na projeção. Os elencos que são usados em outros lugares não são traduzidos e acabam por ser ignorados. Além dos nomes de função SQL, o SQL realmente só executa o equivalente ao Common Language Runtime (CLR). Convert Ou seja, o SQL pode alterar o valor de um tipo para outro. Não há equivalente ao CLR cast porque não há nenhum conceito de reinterpretar os mesmos bits que os de outro tipo. É por isso que um elenco em C# funciona apenas localmente. Não é remoto.

Os operadores, is e as, e o método GetType não se restringem ao operador Select. Eles também podem ser usados em outros operadores de consulta.

Suporte ao SQL Server 2008

A partir do .NET Framework 3.5 SP1, o LINQ to SQL oferece suporte ao mapeamento para novos tipos de data e hora introduzidos com o SQL Server 2008. Mas, há algumas limitações para os operadores de consulta LINQ to SQL que você pode usar ao operar em relação a valores mapeados para esses novos tipos.

Operadores de consulta sem suporte

Os operadores de consulta a seguir não têm suporte em valores mapeados para os novos tipos de data e hora do SQL Server: DATETIME2, DATE, TIMEe DATETIMEOFFSET.

  • Aggregate

  • Average

  • LastOrDefault

  • OfType

  • Sum

Para obter mais informações sobre como mapear para esses tipos de data e hora do SQL Server, consulte SQL-CLR Type Mapping.

Suporte ao SQL Server 2005

O LINQ to SQL não oferece suporte aos seguintes recursos do SQL Server 2005:

  • Procedimentos armazenados escritos para SQL CLR.

  • Tipo definido pelo usuário.

  • Recursos de consulta XML.

Suporte ao SQL Server 2000

As seguintes limitações do SQL Server 2000 (em comparação com o Microsoft SQL Server 2005) afetam o suporte ao LINQ to SQL.

Operadores de aplicação cruzada e aplicação externa

Esses operadores não estão disponíveis no SQL Server 2000. O LINQ to SQL tenta uma série de regravações para substituí-las por junções apropriadas.

Cross Apply e Outer Apply são gerados para navegações de relacionamento. O conjunto de consultas para as quais tais regravações são possíveis não está bem definido. Por esse motivo, o conjunto mínimo de consultas com suporte para o SQL Server 2000 é o conjunto que não envolve navegação de relacionamento.

texto / ntexto

Os tipos text / ntext de dados não podem ser usados em determinadas operações de consulta em relação ao varchar(max) / nvarchar(max), que são suportados pelo Microsoft SQL Server 2005.

Nenhuma resolução está disponível para esta limitação. Especificamente, não pode utilizar Distinct() em qualquer resultado que contenha membros que estejam mapeados para as colunas text ou ntext.

Comportamento acionado por consultas aninhadas

O vinculador do SQL Server 2000 (até SP4) tem algumas idiossincrasias que são desencadeadas por consultas aninhadas. O conjunto de consultas SQL que aciona essas idiossincrasias não está bem definido. Por esse motivo, não é possível definir o conjunto de consultas LINQ to SQL que podem causar exceções do SQL Server.

Operadores de Pular e Levar

Take e Skip têm certas limitações quando são usados em consultas no SQL Server 2000. Para obter mais informações, consulte a entrada "Ignorar e Obter Exceções no SQL Server 2000" em Solução de Problemas.

Materialização de Objetos

A materialização cria objetos CLR a partir de linhas que são retornadas por uma ou mais consultas SQL.

  • As seguintes chamadas são executadas localmente como parte da materialização:

    • Construtores

    • ToString Métodos em projeções

    • Tipos de moldes em projeções

  • Os métodos que seguem o AsEnumerable método são executados localmente. Este método não causa execução imediata.

  • Você pode usar a struct como o tipo de retorno de um resultado de consulta ou como um membro do tipo de resultado. As entidades devem ser classes. Tipos anônimos são materializados como instâncias de classe, mas estruturas nomeadas (não-entidades) podem ser usadas na projeção.

  • Um membro do tipo de retorno de um resultado de consulta pode ser do tipo IQueryable<T>. Materializa-se como uma coleção local.

  • Os seguintes métodos causam a materialização imediata da sequência à qual os métodos são aplicados:

Ver também