Language Integrated Query ( LINQ , pronunciado "link") es un componente de Microsoft .NET Framework que agrega capacidades de consulta de datos nativas a los lenguajes .NET , lanzado originalmente como una parte importante de .NET Framework 3.5 en 2007.
LINQ extiende el lenguaje mediante la adición de expresiones de consulta , que son similares a las sentencias SQL , y se pueden utilizar para extraer y procesar cómodamente datos de matrices , clases enumerables , documentos XML , bases de datos relacionales y fuentes de datos de terceros. Otros usos, que utilizan expresiones de consulta como un marco general para componer de forma legible cálculos arbitrarios, incluyen la construcción de controladores de eventos [1] o analizadores monádicos . [2] También define un conjunto de nombres de métodos (llamados operadores de consulta estándar u operadores de secuencia estándar ), junto con reglas de traducción utilizadas por el compilador para traducir expresiones de sintaxis de consulta en expresiones que utilizan estilo fluido (llamado sintaxis de método por Microsoft) con estos nombres de método, expresiones lambda y tipos anónimos .
A continuación, las descripciones de los operadores se basan en la aplicación del trabajo con colecciones. Muchos de los operadores toman otras funciones como argumentos. Estas funciones pueden proporcionarse en forma de un método con nombre o una función anónima.
El conjunto de operadores de consulta definidos por LINQ se expone al usuario como la API de Operadores de consulta estándar (SQO) . Los operadores de consulta admitidos por la API son: [3]
Estos operadores toman opcionalmente una función que recupera un valor numérico determinado de cada elemento de la colección y lo utiliza para encontrar la suma, el valor mínimo, el valor máximo o el valor promedio de todos los elementos de la colección, respectivamente. Las versiones sobrecargadas no toman ninguna función y actúan como si la identidad se diera como lambda.
Una suma/mín./máx. generalizada. Este operador utiliza una función que especifica cómo se combinan dos valores para formar un resultado intermedio o final. Opcionalmente, se puede proporcionar un valor inicial, lo que permite que el tipo de resultado de la agregación sea arbitrario. Además, se puede proporcionar una función de finalización, que lleva el resultado de la agregación a otro valor. Esto implementa la función de orden superior Fold .
IGrouping<Key, Values>
objetos para cada valor clave distinto. Los IGrouping
objetos se pueden utilizar para enumerar todos los objetos para un valor clave en particular.La API del operador de consulta estándar también especifica ciertos operadores que convierten una colección en otro tipo: [3]
IEnumerable<T>
. [4]IQueryable<T>
.T[]
a partir de la colección.List<T>
de la colección.Dictionary<K, T>
de la colección, indexado por la clave K. Una función de proyección suministrada por el usuario extrae una clave de cada elemento.Lookup<K, T>
de la colección, indexado por la clave K. Una función de proyección suministrada por el usuario extrae una clave de cada elemento.IEnumerable
Cast: convierte una colección no genérica en una de IEnumerable<T>
convirtiendo cada elemento al tipo T
. Alternativamente, convierte un genérico IEnumerable<T>
en otro genérico IEnumerable<R>
convirtiendo cada elemento del tipo T
al tipo R
. Lanza una excepción si cualquier elemento no se puede convertir al tipo indicado.IEnumerable
OfType: convierte una colección no genérica en una de IEnumerable<T>
. Alternativamente, convierte un genérico IEnumerable<T>
en otro genérico IEnumerable<R>
al intentar convertir cada elemento de un tipo T
a otro tipo R
. En ambos casos, solo se incluye el subconjunto de elementos que se convirtieron correctamente al tipo de destino. No se lanzan excepciones.Si bien LINQ se implementa principalmente como una biblioteca para .NET Framework 3.5, también define extensiones de lenguaje opcionales que hacen de las consultas una construcción de lenguaje de primera clase y proporcionan sintaxis para escribir consultas. Estas extensiones de lenguaje se implementaron inicialmente en C# 3.0, [5] : 75 VB 9.0 , F# [6] y Oxygene , y otros lenguajes como Nemerle han anunciado soporte preliminar. Las extensiones de lenguaje incluyen: [7]
var
palabra clave . En VB9.0, la Dim
palabra clave sin declaración de tipo logra lo mismo. Dichos objetos siguen estando fuertemente tipados ; para estos objetos, el compilador infiere los tipos de variables mediante inferencia de tipo , lo que permite especificar y definir los resultados de las consultas sin declarar el tipo de las variables intermedias.Por ejemplo, en la consulta para seleccionar todos los objetos de una colección con SomeProperty
menos de 10,
var resultados = de c en SomeCollection donde c . SomeProperty < 10 seleccione nuevo { c . SomeProperty , c . OtherProperty }; foreach ( var resultado en resultados ) { Console.WriteLine ( resultado ) ; }
Los tipos de variables result , c y results son todos inferidos por el compilador de acuerdo con las firmas de los métodos finalmente utilizados. La base para elegir los métodos está formada por la expresión de consulta de traducción libre result
var resultados = SomeCollection . Donde ( c => c . SomeProperty < 10 ) . Select ( c => new { c . SomeProperty , c . OtherProperty }); resultados . ForEach ( x => { Console . WriteLine ( x . ToString ());})
La especificación C#3.0 define un patrón de expresión de consulta junto con reglas de traducción de una expresión LINQ a una expresión en un subconjunto de C# 3.0 sin expresiones LINQ. La traducción así definida no tiene tipo, lo que, además de que las expresiones lambda se pueden interpretar como delegados o árboles de expresión, permite un alto grado de flexibilidad para las bibliotecas que desean exponer partes de su interfaz como cláusulas de expresión LINQ. Por ejemplo, LINQ to Objects funciona en IEnumerable<T>
s y con delegados, mientras que LINQ to SQL utiliza los árboles de expresión.
Los árboles de expresión son el núcleo del mecanismo de extensibilidad de LINQ, mediante el cual LINQ se puede adaptar a muchas fuentes de datos. Los árboles de expresión se entregan a los proveedores de LINQ, que son implementaciones específicas de la fuente de datos que adaptan las consultas LINQ para que se utilicen con la fuente de datos. Si así lo deciden, los proveedores de LINQ analizan los árboles de expresión contenidos en una consulta para generar las piezas esenciales necesarias para la ejecución de una consulta. Pueden ser fragmentos de SQL o cualquier otra representación de código completamente diferente como datos manipulables adicionales. LINQ viene con proveedores de LINQ para colecciones de objetos en memoria, bases de datos de Microsoft SQL Server , conjuntos de datos ADO.NET y documentos XML. Estos diferentes proveedores definen los diferentes tipos de LINQ:
El proveedor LINQ to Objects se utiliza para colecciones en memoria, utilizando el motor de ejecución de consultas local de LINQ. El código generado por este proveedor hace referencia a la implementación de los operadores de consulta estándar tal como se define en el Sequence
patrón y permite IEnumerable<T>
que las colecciones se consulten localmente. La implementación actual de LINQ to Objects realiza comprobaciones de implementación de interfaz para permitir pruebas de pertenencia rápidas, recuentos y operaciones de búsqueda indexada cuando son compatibles con el tipo de tiempo de ejecución de IEnumerable. [8] [9] [10]
El proveedor LINQ to XML convierte un documento XML en una colección de XElement
objetos, que luego se consultan utilizando el motor de ejecución local que se proporciona como parte de la implementación del operador de consulta estándar. [11]
El proveedor LINQ to SQL permite utilizar LINQ para consultar bases de datos de Microsoft SQL Server , incluidas las bases de datos SQL Server Compact . Dado que los datos de SQL Server pueden residir en un servidor remoto y que SQL Server tiene su propio motor de consultas, LINQ to SQL no utiliza el motor de consultas de LINQ. En su lugar, convierte una consulta LINQ en una consulta SQL que luego se envía a SQL Server para su procesamiento. [12] Sin embargo, dado que SQL Server almacena los datos como datos relacionales y LINQ trabaja con datos encapsulados en objetos, las dos representaciones deben asignarse entre sí. Por este motivo, LINQ to SQL también define un marco de asignación. La asignación se realiza definiendo clases que corresponden a las tablas de la base de datos y que contienen todas o un subconjunto de las columnas de la tabla como miembros de datos. [13] La correspondencia, junto con otros atributos del modelo relacional , como las claves principales , se especifican utilizando atributos definidos por LINQ to SQL . Por ejemplo,
[Tabla(Nombre="Clientes")] clase pública Cliente { [Columna(IsPrimaryKey = true)] int público CustID ; [Columna] cadena pública CustName ; }
Esta definición de clase se asigna a una tabla denominada Customers
y los dos miembros de datos corresponden a dos columnas. Las clases deben definirse antes de poder utilizar LINQ to SQL. Visual Studio 2008 incluye un diseñador de asignaciones que se puede utilizar para crear la asignación entre los esquemas de datos en el objeto, así como el dominio relacional. Puede crear automáticamente las clases correspondientes a partir de un esquema de base de datos , así como permitir la edición manual para crear una vista diferente utilizando solo un subconjunto de las tablas o columnas de una tabla. [13]
El mapeo se implementa mediante el DataContext
que toma una cadena de conexión al servidor y se puede utilizar para generar un Table<T>
donde T es el tipo al que se mapeará la tabla de la base de datos. El Table<T>
encapsula los datos en la tabla e implementa la IQueryable<T>
interfaz, de modo que se crea el árbol de expresiones, que maneja el proveedor LINQ to SQL. Convierte la consulta en T-SQL y recupera el conjunto de resultados del servidor de la base de datos. Dado que el procesamiento ocurre en el servidor de la base de datos, no se pueden utilizar los métodos locales, que no están definidos como parte de las expresiones lambda que representan los predicados. Sin embargo, puede utilizar los procedimientos almacenados en el servidor. Se realiza un seguimiento de cualquier cambio en el conjunto de resultados y se puede enviar de vuelta al servidor de la base de datos. [13]
Dado que el proveedor LINQ to SQL (arriba) funciona únicamente con bases de datos de Microsoft SQL Server , para poder admitir cualquier base de datos genérica, LINQ también incluye LINQ to DataSets. Utiliza ADO.NET para gestionar la comunicación con la base de datos. Una vez que los datos están en los conjuntos de datos ADO.NET, LINQ to DataSets ejecuta consultas en estos conjuntos de datos. [14]
Los usuarios no profesionales pueden tener dificultades con las sutilezas de las características y la sintaxis de LINQ to Objects . Los patrones de implementación ingenuos de LINQ pueden provocar una degradación catastrófica del rendimiento. [15] [16]
El rendimiento de LINQ to XML y LINQ to SQL en comparación con ADO.NET depende del caso de uso. [17] [18]
La versión 4 del marco .NET incluye PLINQ , o Parallel LINQ , un motor de ejecución paralela para consultas LINQ. Define la ParallelQuery<T>
clase. Cualquier implementación de la IEnumerable<T>
interfaz puede aprovechar el motor PLINQ llamando al AsParallel<T>(this IEnumerable<T>)
método de extensión definido por la clase ParallelEnumerable en el espacio de nombres System.Linq del marco .NET. [19] El motor PLINQ puede ejecutar partes de una consulta simultáneamente en varios subprocesos, lo que proporciona resultados más rápidos. [20]
Muchos de los conceptos que introdujo LINQ se probaron originalmente en el proyecto de investigación Cω de Microsoft , anteriormente conocido con los nombres en código X# (X Sharp) y Xen . Se le cambió el nombre a Cω después de que se integrara en él Polyphonic C# (otro lenguaje de investigación basado en principios de cálculo de uniones ).
Cω intenta hacer que los almacenes de datos (como bases de datos y documentos XML ) sean accesibles con la misma facilidad y seguridad de tipos que los tipos tradicionales como cadenas y matrices . Muchas de estas ideas fueron heredadas de un proyecto de incubación anterior dentro del equipo WebData XML llamado X# y Xen. Cω también incluye nuevas construcciones para soportar la programación concurrente ; estas características se derivaron en gran medida del proyecto anterior Polyphonic C#. [21]
Disponible por primera vez en 2004 como una vista previa del compilador, las características de Cω fueron posteriormente utilizadas por Microsoft en la creación de las características LINQ lanzadas en 2007 en la versión 3.5 de .NET [22] Las construcciones de concurrencia también han sido lanzadas en una forma ligeramente modificada como una biblioteca, llamada Joins Concurrency Library , para C# y otros lenguajes .NET por Microsoft Research . [23]
Existen puertos de LINQ para PHP (PHPLinq), JavaScript (linq.js), TypeScript (linq.ts) y ActionScript (ActionLinq), aunque ninguno es estrictamente equivalente a LINQ en los lenguajes inspirados en .NET C#, F# y VB.NET (donde es parte del lenguaje, no una biblioteca externa, y donde a menudo aborda una gama más amplia de necesidades). [ cita requerida ]
bien es cierto que LINQ es potente y muy eficiente, los grandes conjuntos de datos aún pueden causar problemas de rendimiento inesperados.
llamar a una consulta varias veces con Entity Framework, el enfoque recomendado es utilizar consultas LINQ compiladas. La compilación de una consulta da como resultado un impacto en el rendimiento la primera vez que se utiliza la consulta, pero las llamadas posteriores se ejecutan mucho más rápido.