Traslación del operador de consulta estándar
LINQ to SQL convierte los operadores de consulta estándar en comandos SQL. El procesador de consultas de la base de datos determina la semántica de ejecución de la conversión a SQL.
Los operadores de consulta estándar se definen en secuencias. Una secuencia se ordena y se basa en la identidad de referencia de cada elemento de la secuencia. Para más información, consulte Información general sobre operadores de consulta estándar (C#) o Información general sobre operador de consulta estándar (Visual Basic).
SQL trata principalmente con conjuntos de valores no ordenados. La ordenación es normalmente una operación de procesamiento posterior declarada de forma explícita que se aplica al resultado final de una consulta en lugar de a los resultados intermedios. La identidad se define con valores. Por esta razón se entiende que las consultas SQL tratan con conjuntos múltiples (bolsas) en lugar de conjuntos.
En los párrafos siguientes se describen las diferencias entre los operadores de consulta estándar y su conversión a SQL para el proveedor de SQL Server de LINQ to SQL.
Compatibilidad de los operadores
Concat
El método Concat se define para los conjuntos múltiples ordenados cuando el orden del receptor y el orden del argumento son iguales. Concat funciona como UNION ALL
sobre los conjuntos múltiples después del orden común.
El último paso es ordenar en SQL antes de que se generen los resultados. Concat no conserva el orden de sus argumentos. Para garantizar una ordenación correcta, debe ordenar explícitamente los resultados de Concat.
Intersect, Except, Union
Los métodos Intersect y Except se definen bien solo en los conjuntos. La semántica de conjuntos múltiples no está definida.
El método Union se define para los conjuntos múltiples como la concatenación no ordenada de los conjuntos múltiples (de hecho, el resultado de la cláusula UNION ALL en SQL).
Take, Skip
Los métodos Take y Skip están bien definidos solo en conjuntos ordenados. La semántica para los conjuntos no ordenados o conjuntos múltiples no está definida.
Nota
Take y Skip tienen ciertas limitaciones cuando se utilizan en consultas en SQL Server 2000. Para obtener más información, consulte la entrada "Omitir y tomar excepciones en SQL Server 2000" en Solución de problemas.
Debido a las limitaciones de la ordenación en SQL, LINQ to SQL intenta trasladar la ordenación del argumento de estos métodos al resultado del método. Por ejemplo, considere la siguiente consulta SQL de 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
El SQL generado para este código traslada la ordenación al final, como se observa a continuación:
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]
Parece obvio que toda la ordenación especificada debe ser coherente cuando se encadenan Take y Skip. De lo contrario, los resultados no están definidos.
Tanto Take como Skip están bien definidos para los argumentos integrales de constante no negativos basados en la especificación de operadores de consulta estándar.
Operadores sin conversión
Los siguientes métodos no son traducidos por LINQ to SQL. La razón más común es la diferencia entre los conjuntos múltiples no ordenados y las secuencias.
Operadores | Análisis razonado |
---|---|
TakeWhile, SkipWhile | Las consultas SQL funcionan con conjuntos múltiples, no con secuencias. ORDER BY debe ser la última cláusula aplicada a los resultados. Por esta razón, no hay ninguna conversión general para estos dos métodos. |
Reverse | La conversión de este método es posible para un conjunto ordenado pero LINQ to SQL no la realiza actualmente. |
Last, LastOrDefault | La conversión de estos métodos es posible para un conjunto ordenado pero LINQ to SQL no la realiza actualmente. |
ElementAt, ElementAtOrDefault | Las consultas SQL funcionan en conjuntos múltiples, no en secuencias indizables. |
DefaultIfEmpty (sobrecarga con argumento predeterminado) | En general, no se puede especificar un valor predeterminado para una tupla arbitraria. Los valores nulos para las tuplas son posibles en algunos casos a través de combinaciones externas. |
Conversión de expresiones
Semántica de valores null
LINQ to SQL no impone las semántica de comparación de valores null en SQL. Los operadores de comparación se convierten sintácticamente en sus equivalentes SQL. Por esta razón, la semántica refleja la semántica de SQL definida según la configuración del servidor o la conexión. Dos valores nulos se consideran distintos según la configuración predeterminada de SQL Server (aunque se puede cambiar la configuración para cambiar la semántica). LINQ to SQL no tiene en cuenta la configuración del servidor cuando convierte las consultas.
Una comparación con el literal null se convierte a la versión de SQL correcta (is null
o is not null
).
SQL Server define el valor null
en la intercalación. LINQ to SQL no cambia la intercalación.
Agregados
El método de agregado del operador de consulta estándar Sum se evalúa como cero para una secuencia vacía o para una secuencia que solo contiene valores nulos. En LINQ to SQL, la semántica de SQL se mantiene invariable y Sum se evalúa como null
en lugar de cero para una secuencia vacía o para una secuencia que solo contiene valores nulos.
En LINQ to SQL se aplican las restricciones de SQL para los agregados en los resultados intermedios. Sum para cantidades enteras de 32 bits no se calcula utilizando los resultados de 64 bits. Puede producirse un desbordamiento en la conversión de LINQ to SQL que realiza Sum aun cuando la implementación del operador de consulta estándar no produce un desbordamiento para la secuencia en memoria correspondiente.
De igual forma, la traslación que realiza LINQ to SQL de Average de valores enteros se calcula como integer
, no como double
.
Argumentos de entidad
LINQ to SQL permite utilizar los tipos de entidad en los métodos GroupBy y OrderBy. En la conversión de estos operadores, el uso de un argumento de un tipo se considera equivalente a especificar todos los miembros de ese tipo. Por ejemplo, el código siguiente es 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 equivalentes o comparables
La igualdad de los argumentos se requiere en la implementación de los métodos siguientes:
LINQ to SQL admite la igualdad y comparación para los argumentos planos, pero no para los argumentos que son secuencias o las contienen. Un argumento plano es un tipo que asignarse a una fila de SQL. Una proyección de uno o más tipos de entidad que se pueden determinar estáticamente que no contiene una secuencia se considera un argumento plano.
Los siguientes son ejemplos de argumentos planos:
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})
Los siguientes son ejemplos de argumentos no planos (jerá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)
Conversión de funciones de Visual Basic
Las siguientes funciones del asistente que utiliza el compilador de Visual Basic se convierten a las funciones y operadores de SQL correspondientes:
CompareString
DateTime.Compare
Decimal.Compare
IIf (in Microsoft.VisualBasic.Interaction)
Métodos de conversión:
ToBoolean
ToSByte
ToByte
ToChar
ToCharArrayRankOne
ToDate
ToDecimal
ToDouble
ToInteger
ToUInteger
ToLong
ToULong
ToShort
ToUShort
ToSingle
ToString
Compatibilidad de herencia
Restricciones de la asignación de herencia
Para más información, consulte Asignación de jerarquías de herencia.
Herencia en consultas
Las conversión de tipos de C# solo se admite en la proyección. Las conversiones de tipos que se utilizan en otra parte no se convierten y se omiten. Además de los nombres de función de SQL, SQL realmente solo realiza la operación equivalente a Convert de Common Language Runtime (CLR). Es decir, SQL puede cambiar el valor de un tipo a otro. No hay ningún equivalente de conversión de tipos de CLR porque no existe el concepto de reinterpretar los mismos bits que los de otro tipo. Por esa razón una conversión de tipos de C# solo funciona localmente. No es remota.
Los operadores, is
y as
, y el método GetType
no están limitados al operador Select
. También se pueden utilizar en otros operadores de consulta.
Compatibilidad con SQL Server 2008
A partir de .NET Framework 3.5 Service Pack 1, LINQ to SQL admite la asignación a tipos nuevos de fecha y hora incorporados con SQL Server 2008. Pero, hay algunas limitaciones en los operadores de consulta de LINQ to SQL que puede usar al operar con valores asignados a estos tipos nuevos.
Operadores de consulta no admitidos
Los operadores de consulta siguientes no se admiten en valores asignados a los nuevos tipos de fecha y hora de SQL Server: DATETIME2
, DATE
, TIME
y DATETIMEOFFSET
.
Aggregate
Average
LastOrDefault
OfType
Sum
Para obtener más información sobre la asignación a estos tipos de fecha y hora de SQL Server, vea Asignación del tipo SQL-CLR.
Compatibilidad con SQL Server 2005
LINQ to SQL no admite las características de SQL Server 2005 siguientes:
Procedimientos almacenados escritos para SQL CLR.
Tipo definido por el usuario.
Características de consulta XML.
Compatibilidad con SQL Server 2000
Las siguientes limitaciones de SQL Server 2000 (en comparación con Microsoft SQL Server 2005) afectan a LINQ to SQL soporte técnico.
Operadores Cross Apply y Outer Apply
Estos operadores no están disponibles en SQL Server 2000. LINQ to SQL intenta una serie de operaciones de reescritura para sustituirlos por las combinaciones adecuadas.
Cross Apply
y Outer Apply
se generan para la navegación de relaciones. El conjunto de consultas para el que son posibles tales operaciones de reescritura no está bien definido. Por esta razón, el conjunto mínimo de consultas que se admite para SQL Server 2000 es el conjunto que no implica la navegación de relaciones.
text / ntext
Los tipos de datos text
/ ntext
no se pueden utilizar en ciertas operaciones de consulta con varchar(max)
/ nvarchar(max)
, que son admitidos por Microsoft SQL Server 2005.
Esta limitación no tiene ninguna resolución. Concretamente, no puede utilizar Distinct()
en ningún resultado que contenga miembros que se asignen a columnas text
o ntext
.
Comportamiento desencadenado por las consultas anidadas
El enlazador de SQL Server 2000 (hasta SP4) tiene algunas peculiaridades que son desencadenadas por las consultas anidadas. El conjunto de consultas SQL que las desencadenan no está bien definido. Por esta razón, no se puede definir el conjunto de consultas LINQ to SQL que podrían producir excepciones de SQL Server.
Operadores Skip y Take
Take y Skip tienen ciertas limitaciones cuando se utilizan en consultas en SQL Server 2000. Para obtener más información, consulte la entrada "Omitir y tomar excepciones en SQL Server 2000" en Solución de problemas.
Materialización de objetos
La materialización crea objetos CLR a partir de las filas devueltas por una o más consultas SQL.
Las llamadas siguientes se ejecutan localmente como parte de la materialización:
Constructores
Métodos
ToString
en las proyeccionesConversiones de tipos en las proyecciones
Los métodos que siguen al método AsEnumerable se ejecutan localmente. Este método no produce la ejecución inmediata.
Puede utilizar
struct
como tipo de valor devuelto en el resultado de una consulta o como un miembro del tipo de resultado. Las entidades deben ser clases. Los tipos anónimos se materializan como instancias de clase, pero los structs con nombre (no entidades) se pueden utilizar en la proyección.Un miembro del tipo de valor devuelto en el resultado de una consulta puede ser de tipo IQueryable<T>. Se materializa como una colección local.
Los métodos siguientes provocan la materialización inmediata de la secuencia a la que se aplican los métodos: