Language Integrated Query ( LINQ , pronunciado "link") es un componente del marco de trabajo Microsoft .NET que añade capacidades nativas de consulta de datos a los lenguajes .NET , lanzado originalmente como 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 usar para extraer y procesar datos de manera conveniente 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 cálculos arbitrarios de manera legible, incluyen la construcción de manejadores 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 que el compilador utiliza para traducir expresiones de sintaxis de consulta en expresiones que utilizan el estilo fluido (llamado sintaxis de método por Microsoft) con estos nombres de métodos, expresiones lambda y tipos anónimos .
Arquitectura
API de operador de consulta estándar
A continuación, las descripciones de los operadores se basan en su aplicación al trabajo con colecciones. Muchos de los operadores aceptan otras funciones como argumentos. Estas funciones pueden proporcionarse en forma de método con nombre o función anónima.
El conjunto de operadores de consulta definidos por LINQ se expone al usuario como la interfaz de programación de aplicaciones ( API ) Standard Query Operator (SQO). Los operadores de consulta compatibles con la API son: [ 3 ]
Select
El Selectoperador realiza una proyección sobre la colección para seleccionar aspectos relevantes de los elementos. El usuario proporciona una función arbitraria, en forma de expresión lambda o con nombre , que proyecta los miembros de datos. Esta función se pasa al operador como delegado . Esto implementa la función de orden superior Map .
Where
El Whereoperador permite definir un conjunto de reglas de predicado que se evalúan para cada objeto de la colección, mientras que los objetos que no coinciden con la regla se filtran. El predicado se proporciona al operador como un delegado. Esto implementa la función de orden superior Filter .
SelectMany
Para una asignación proporcionada por el usuario de elementos de colección a colecciones, se realizan semánticamente dos pasos. Primero, cada elemento se asigna a su colección correspondiente. Segundo, el resultado del primer paso se aplana un nivel. Selecty Whereson ambos implementables en términos de SelectMany, siempre que estén disponibles colecciones singleton y vacías. Las reglas de traducción mencionadas anteriormente aún hacen que sea obligatorio para un proveedor LINQ proporcionar los otros dos operadores. Esto implementa la función de orden superior Bind .
Sum, Min, Max,Average
Estos operadores pueden recibir opcionalmente una función que recupera un valor numérico de cada elemento de la colección y lo utiliza para calcular la suma, el mínimo, el máximo o el promedio de todos los elementos de la colección, respectivamente. Las versiones sobrecargadas no reciben ninguna función y actúan como si la identidad se proporcionara como la función lambda.
Aggregate
Un operador generalizado // SumEste operador toma 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 transforma el resultado de la agregación en otro valor. Esto implementa la función de orden superior Fold .MinMax
Join,GroupJoin
El Joinoperador realiza una unión interna en dos colecciones, basándose en las claves coincidentes de los objetos en cada colección. Recibe dos funciones como delegados, una para cada colección, que ejecuta en cada objeto de la colección para extraer la clave del objeto. También recibe otro delegado en el que el usuario especifica qué elementos de datos, de los dos elementos coincidentes, deben usarse para crear el objeto resultante. El GroupJoinoperador realiza una unión de grupo . Al igual que el Selectoperador, los resultados de una unión son instancias de una clase diferente, con todos los miembros de datos de ambos tipos de los objetos de origen, o un subconjunto de ellos.
Take,TakeWhile
El Takeoperador selecciona los primeros nobjetos de una colección, mientras que el TakeWhileoperador, que toma un predicado, selecciona aquellos objetos que coinciden con el predicado (deteniéndose en el primer objeto que no coincide con él).
Skip,SkipWhile
Los operadores Skipy son complementos de y - omiten los primeros objetos de una colección, o aquellos objetos que coinciden con un predicado (en el caso de ).SkipWhileTakeTakeWhilenSkipWhile
OfType
Este OfTypeoperador se utiliza para seleccionar elementos de un tipo determinado.
Concat
El Concatoperador concatena dos colecciones.
OrderBy,ThenBy
El OrderByoperador se utiliza para especificar el orden de clasificación principal de los elementos de una colección según una clave. El orden predeterminado es ascendente; para invertirlo, OrderByDescendingse debe usar el operador. ThenByEste operador ThenByDescendingespecifica el orden subsiguiente de los elementos. La función para extraer el valor de la clave del objeto la especifica el usuario como delegado.
Reverse
El Reverseoperador revierte una colección.
GroupBy
El GroupByoperador toma una función que extrae un valor clave y devuelve una colección de System.Linq.IGrouping<K, V>objetos, uno por cada valor clave distinto. Estos System.Linq.IGrouping<K, V>objetos se pueden usar para enumerar todos los objetos asociados a un valor clave específico.
Distinct
Este Distinctoperador elimina las instancias duplicadas de un objeto de una colección. Una sobrecarga de este operador acepta un objeto comparador de igualdad que define los criterios de distinción.
Union, Intersect,Except
Estos operadores se utilizan para realizar operaciones de unión , intersección y diferencia entre dos secuencias, respectivamente. Cada uno tiene una sobrecarga que acepta un objeto comparador de igualdad que define los criterios de igualdad de los elementos.
SequenceEqual
El SequenceEqualoperador determina si todos los elementos de dos colecciones son iguales y están en el mismo orden.
First, FirstOrDefault, Last,LastOrDefault
Estos operadores toman un predicado. El Firstoperador devuelve el primer elemento para el cual el predicado es verdadero o, si no hay coincidencias, lanza una excepción. El FirstOrDefaultoperador es similar al Firstoperador excepto que devuelve el valor predeterminado para el tipo de elemento (generalmente una referencia nula ) en caso de que no haya coincidencias con el predicado. El Lastoperador recupera el último elemento que coincide con el predicado o lanza una excepción en caso de que no haya coincidencias. LastOrDefaultDevuelve el valor predeterminado del elemento si no hay coincidencias.
Single,SingleOrDefault
El Singleoperador recibe un predicado y devuelve el elemento que coincide con dicho predicado. Se genera una excepción si ninguno o más de un elemento coinciden con el predicado.
El SingleOrDefaultoperador recibe un predicado y devuelve el elemento que coincide con él. Si hay más de un elemento que coincide, se lanza una excepción. Si ningún elemento coincide, se devuelve un valor predeterminado.
ElementAt
El ElementAtoperador recupera el elemento en un índice determinado de la colección.
Any,All
El Anyoperador comprueba si hay algún elemento en la colección que coincida con el predicado. No selecciona el elemento, sino que devuelve verdadero si al menos uno coincide. Una llamada a `any` sin predicado devuelve verdadero si la colección no está vacía. El Alloperador devuelve verdadero si todos los elementos coinciden con el predicado.
Contains
El Containsoperador comprueba si la colección contiene un elemento determinado.
Count
El Countoperador cuenta el número de elementos en la colección dada. Una sobrecarga que recibe un predicado cuenta el número de elementos que coinciden con dicho predicado.
Convertir una colección en otro tipo
La API del operador de consulta estándar también especifica ciertos operadores que convierten una colección en otro tipo: [ 3 ]
AsEnumerable: Tipifica estáticamente la colección como unSystem.Collections.Generic.IEnumerable<T>. [ 4 ]AsQueryable: Tipifica estáticamente la colección como unSystem.Linq.IQueryable<T>.ToArray: Crea una matrizT[]a partir de la colección.ToList: Crea un objetoSystem.Collections.Generic.List<T>a partir de la colección.ToDictionary: Crea un objetoSystem.Collections.Generic.Dictionary<K, V>a partir de la colección, indexado por la claveK. Una función de proyección proporcionada por el usuario extrae una clave de cada elemento.ToLookup: Crea un objetoSystem.Linq.Lookup<K, V>a partir de la colección, indexado por la claveK. Una función de proyección proporcionada por el usuario extrae una clave de cada elemento.Cast: convierte una colección no genéricaSystem.Collections.IEnumerableen unaSystem.Collections.Generic.IEnumerable<T>de convirtiendo cada elemento al tipoT. Alternativamente, convierte una colección genéricaSystem.Collections.Generic.IEnumerable<T>en otra genéricaSystem.Collections.Generic.IEnumerable<R>convirtiendo cada elemento del tipoTal tipoR. Lanza una excepción si algún elemento no se puede convertir al tipo indicado.OfTypeSystem.Collections.IEnumerable: convierte una colección no genérica en una deSystem.Collections.Generic.IEnumerable<T>. Alternativamente, convierte una colección genéricaSystem.Collections.Generic.IEnumerable<T>en otra genéricaSystem.Collections.Generic.IEnumerable<R>intentando convertir cada elemento del tipoTal tipoR. En ambos casos, solo se incluye el subconjunto de elementos convertidos correctamente al tipo de destino. No se generan excepciones.
extensiones de idioma
Aunque LINQ se implementa principalmente como una biblioteca para .NET Framework 3.5, también define extensiones de lenguaje opcionales que convierten las consultas en una construcción de lenguaje de primera clase y proporcionan azúcar sintáctico para escribir consultas. Estas extensiones de lenguaje se han implementado 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 ]
- Sintaxis de consulta: Un lenguaje puede elegir libremente una sintaxis de consulta que reconozca de forma nativa. Estas palabras clave del lenguaje deben ser traducidas por el compilador a las llamadas a métodos LINQ correspondientes.
- Variables con tipado implícito: Esta mejora permite declarar variables sin especificar sus tipos. Los lenguajes C# 3.0 [ 5 ] : 367 y Oxygene las declaran con la
varpalabra clave. En VB9.0, laDimpalabra clave sin declaración de tipo logra el mismo resultado. Dichos objetos siguen siendo fuertemente tipados ; para estos objetos, el compilador infiere los tipos de las variables mediante inferencia de tipos , lo que permite especificar y definir los resultados de las consultas sin declarar el tipo de las variables intermedias. - Tipos anónimos : Los tipos anónimos permiten que el compilador infiera clases que contienen únicamente declaraciones de miembros de datos. Esto resulta útil para los operadores Select y Join, cuyos tipos de resultado pueden diferir de los tipos de los objetos originales. El compilador utiliza la inferencia de tipos para determinar los campos contenidos en las clases y genera métodos de acceso y modificación para dichos campos.
- Inicializador de objetos : Los inicializadores de objetos permiten crear e inicializar un objeto en un único ámbito, tal como se requiere para los operadores Select y Join.
- Expresiones Lambda : Las expresiones Lambda permiten escribir predicados y otras funciones de proyección directamente en la página con una sintaxis concisa, y admiten el cierre léxico completo. Se capturan en parámetros como delegados o árboles de expresiones, según el proveedor de consultas.
Por ejemplo, en la consulta para seleccionar todos los objetos de una colección con SomePropertymenos de 10,
using System ; using System.Collections.Generic ;IEnumerable < MyObject > SomeCollection = /* algo aquí */ ;IEnumerable < MyObject > results = from c in SomeCollection where c . SomeProperty < 10 select new { c . SomeProperty , c . OtherProperty };foreach ( MyObject result in results ) { Console . WriteLine ( result ); }Los tipos de variables result, cy resultstodos son inferidos por el compilador de acuerdo con las firmas de los métodos que finalmente se utilicen. La base para elegir los métodos está formada por el resultado de la traducción sin expresiones de consulta.
using System ; using System.Collections.Generic ;IEnumerable < MyObject > results = SomeCollection . Where ( c => c . SomeProperty < 10 ) . Select ( c => new { c . SomeProperty , c . OtherProperty });resultados . ForEach ( x => { Console . WriteLine ( x . ToString ());})Proveedores LINQ
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 expresiones, permite una gran flexibilidad para las bibliotecas que deseen exponer partes de su interfaz como cláusulas de expresiones LINQ. Por ejemplo, LINQ to Objects funciona System.Collections.Generic.IEnumerable<T>con delegados, mientras que LINQ to SQL utiliza árboles de expresiones.
Los árboles de expresiones son la base del mecanismo de extensibilidad de LINQ, que permite adaptar LINQ a diversas fuentes de datos. Estos árboles se entregan a los proveedores LINQ, implementaciones específicas de cada fuente de datos que adaptan las consultas LINQ para su uso con dicha fuente. Si lo consideran necesario, los proveedores LINQ analizan los árboles de expresiones de una consulta para generar los elementos esenciales necesarios para su ejecución. Estos pueden ser fragmentos SQL o cualquier otra representación de código completamente distinta, como datos manipulables. LINQ incluye proveedores LINQ para colecciones de objetos en memoria, bases de datos de Microsoft SQL Server , conjuntos de datos ADO.NET y documentos XML. Estos proveedores definen las distintas variantes de LINQ.
LINQ a objetos
El proveedor LINQ to Objects se utiliza para colecciones en memoria, empleando 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 definidos en el Sequencepatrón y permite System.Collections.Generic.IEnumerable<T>consultar colecciones localmente. La implementación actual de LINQ to Objects realiza comprobaciones de implementación de la 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 System.Collections.Generic.IEnumerable<T>. [ 8 ] [ 9 ] [ 10 ]
LINQ to XML (anteriormente llamado XLINQ)
El proveedor LINQ to XML convierte un documento XML en una colección de System.Linq.Xml.XElementobjetos, 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 XML convierte un documento XML en una colección de System.Linq.Xml.XElementobjetos, 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. [ 12 ]
LINQ to SQL (anteriormente llamado DLINQ)
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 consulta, LINQ to SQL no utiliza el motor de consulta de LINQ. En su lugar, convierte una consulta LINQ en una consulta SQL que luego se envía a SQL Server para su procesamiento. [ 13 ] 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 esta razón, 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. [ 14 ] La correspondencia, junto con otros atributos del modelo relacional , como las claves primarias , se especifican mediante atributos definidos por LINQ to SQL . Por ejemplo,
usando System.Data.Linq ;[Table(Name="Customers")] public class Customer { [Column(IsPrimaryKey = true)] public int CustID ;[Columna] public string CustName ; }Esta definición de clase se asigna a una tabla con nombre Customersy los dos miembros de datos corresponden a dos columnas. Las clases deben definirse antes de poder usar LINQ to SQL. Visual Studio 2008 incluye un diseñador de asignaciones que permite crear la asignación entre los esquemas de datos en el dominio de objetos y el 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. [ 14 ]
El mapeo se implementa mediante la System.Data.Linq.DataContextque toma una cadena de conexión al servidor y se puede usar para generar System.Data.Linq.Table<T>donde Tes el tipo al que se mapeará la tabla de la base de datos. System.Data.Linq.Table<T>Encapsula los datos en la tabla e implementa la System.Linq.IQueryable<T>interfaz, de modo que se crea el árbol de expresiones, que maneja el proveedor LINQ to SQL. Convierte la consulta a T-SQL y recupera el conjunto de resultados del servidor de base de datos. Dado que el procesamiento se realiza en el servidor de base de datos, no se pueden usar métodos locales, que no están definidos como parte de las expresiones lambda que representan los predicados. Sin embargo, puede usar los procedimientos almacenados en el servidor. Cualquier cambio en el conjunto de resultados se registra y se puede enviar de vuelta al servidor de base de datos. [ 14 ]
LINQ a conjuntos de datos
Dado que el proveedor LINQ to SQL (mencionado anteriormente) solo funciona con bases de datos de Microsoft SQL Server , para admitir cualquier base de datos genérica, LINQ también incluye LINQ to DataSets. Este utiliza ADO.NET para gestionar la comunicación con la base de datos. Una vez que los datos se encuentran en conjuntos de datos de ADO.NET, LINQ to DataSets ejecuta consultas sobre dichos conjuntos de datos. [ 15 ]
Actuación
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. [ 16 ] [ 17 ]
El rendimiento de LINQ to XML y LINQ to SQL en comparación con ADO.NET depende del caso de uso. [ 18 ] [ 19 ]
PLINQ
La versión 4 del framework .NET incluye Extensiones Paralelas para LINQ Paralelo (PLINQ), un motor de ejecución paralela para consultas LINQ. Define la System.Linq.ParallelQuery<T>clase. Cualquier implementación de la System.Collections.Generic.IEnumerable<T>interfaz puede aprovechar el motor PLINQ llamando al método de extensión definido por el espacio de nombres de la clase del framework .NET. [ 20 ] El motor PLINQ puede ejecutar partes de una consulta simultáneamente en múltiples subprocesos, lo que proporciona resultados más rápidos. [ 21 ]AsParallel<T>(thisIEnumerable<T>)System.Linq.ParallelEnumerable
Lenguas predecesoras
Muchos de los conceptos introducidos por LINQ se probaron originalmente en el proyecto de investigación Cω de Microsoft , conocido anteriormente con los nombres en clave X# (X Sharp) y Xen . Se le cambió el nombre a Cω después de que Polyphonic C# (otro lenguaje de investigación basado en principios de cálculo de unión ) se integrara en él.
Cω intenta 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 se heredaron de un proyecto de incubación anterior dentro del equipo WebData XML llamado X# y Xen. Cω también incluye nuevas construcciones para admitir la programación concurrente ; estas características se derivaron en gran medida del proyecto anterior Polyphonic C#. [ 22 ]
Disponible por primera vez en 2004 como una vista previa del compilador, las características de Cω fueron utilizadas posteriormente por Microsoft en la creación de las características LINQ lanzadas en 2007 en .NET versión 3.5 [ 23 ] 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 . [ 24 ]
Véase también
Referencias
- ↑ "Marco de trabajo Rx" . 10 de junio de 2011.
- ↑ "Combinadores de analizadores sintácticos monádicos usando C#3" . Consultado el 21 de noviembre de 2009 .
- 1 2 "Operadores de consulta estándar" . Microsoft . Consultado el 30 de noviembre de 2007 .
- ↑ "Clase enumerable" . msdn . Microsoft . Consultado el 15 de febrero de 2014 .
- 1 2 Skeet, Jon (23 de marzo de 2019). C# en profundidad . Manning. ISBN 978-1617294532.
- ↑ "Expresiones de consulta (F#)" . Documentación de Microsoft . Consultado el 19 de diciembre de 2012 .
- ↑ "LINQ Framework" . Consultado el 30 de noviembre de 2007 .
- ↑ "Enumerable.ElementAt" . Consultado el 7 de mayo de 2014 .
- ↑ "Enumerable.Contains" . Consultado el 7 de mayo de 2014 .
- ↑ "Enumerable.Count" . Consultado el 7 de mayo de 2014 .
- ↑ "Consulta integrada en el lenguaje .NET para datos XML" . 30 de abril de 2007. Consultado el 30 de noviembre de 2007 .
- ↑ "Consulta integrada en el lenguaje .NET para datos XML" . 30 de abril de 2007. Consultado el 30 de noviembre de 2007 .
- ↑ "LINQ to SQL" . Consultado el 30 de noviembre de 2007 .
{{cite web}}: CS1 maint: servicio de archivado obsoleto ( enlace ) - 1 2 3 "LINQ to SQL: Consulta integrada en el lenguaje .NET para datos relacionales" . 30 de abril de 2007. Recuperado el 30 de noviembre de 2007 .
- ↑ "LINQ to DataSets" . Consultado el 30 de noviembre de 2007 .
{{cite web}}: CS1 maint: servicio de archivado obsoleto ( enlace ) - ↑ Vider, Guy (2007-12-21). "Prueba de rendimiento de LINQ: Mi primer proyecto de Visual Studio 2008" . Recuperado el 2009-02-08 .
- ↑ Parsons, Jared (2008). "Aumentar el rendimiento de las consultas LINQ" . Microsoft Developer Network . Consultado el 19 de marzo de 2014.
Si bien es cierto que LINQ es potente y muy eficiente, los grandes conjuntos de datos aún pueden causar problemas de rendimiento inesperados
. - ↑ Alva, Jaime (06/08/2010). "Posibles problemas de rendimiento con la recompilación de consultas LINQ compiladas" . Microsoft Developer Network . Consultado el 19/03/2014 .
Al llamar a una consulta varias veces con Entity Framework, el enfoque recomendado es usar consultas LINQ compiladas. Compilar una consulta produce una disminución del rendimiento la primera vez que se usa, pero las llamadas posteriores se ejecutan mucho más rápido.
- ↑ Kshitij, Pandey (25 de mayo de 2008). "Comparaciones de rendimiento de LinQ con SQL, ADO y C#" . Recuperado el 8 de febrero de 2009 .
- ↑ "Clase ParallelEnumerable" . Consultado el 7 de mayo de 2014 .
- ↑ "Programación en la era de la concurrencia: Programación concurrente con PFX" . Consultado el 16 de octubre de 2007 .
- ↑ Eichert, Steve; Wooley, James B.; Marguerie, Fabrice (2008). LINQ in Action . Manning. págs. 56–57 (según se indica en el enlace de búsqueda de Google Libros; el libro no tiene números de página). ISBN 9781638354628.
- ↑ Conceptos detrás del lenguaje C# 3.0 | Artículos | TomasP.Net Archivado el 12/02/2007 en Wayback Machine
- ↑ "La biblioteca de concurrencia Joins" . Consultado el 8 de junio de 2007 .
Enlaces externos
- Sitio web oficial de Microsoft
- LINQ to Objects para el desarrollador .NET
- El futuro de LINQ to SQL. Archivado el 21/07/2020 en Wayback Machine.
- ¿Cómo funciona en C#? - Parte 3 (LINQ en C# en detalle)
- Terminología .NET
- Lenguajes de consulta
- Acceso a datos XML