Nota
El acceso a esta página requiere autorización. Puede intentar iniciar sesión o cambiar directorios.
El acceso a esta página requiere autorización. Puede intentar cambiar los directorios.
Los operadores de consulta estándar son las palabras clave y los métodos que forman el patrón LINQ. El lenguaje C# define palabras clave de consulta LINQ que se usan para la expresión de consulta más común. El compilador traduce expresiones mediante estas palabras clave a las llamadas de método equivalentes. Las dos formas son sinónimos. Otros métodos que forman parte del System.Linq espacio de nombres no tienen palabras clave de consulta equivalentes. En esos casos debe usarse la sintaxis del método. En esta sección se tratan todas las palabras clave del operador de consulta. El entorno de ejecución y otros paquetes NuGet agregan más métodos diseñados para trabajar con consultas LINQ en cada versión. Los métodos más comunes, incluidos los que tienen equivalentes de palabra clave de consulta, se tratan en esta sección. Para obtener la lista completa de los métodos de consulta admitidos por .NET Runtime, consulte la documentación de api System.Linq.Enumerable . Además de los métodos descritos aquí, esta clase contiene métodos para concatenar orígenes de datos, calcular un valor único de un origen de datos, como una suma, promedio u otro valor.
Importante
Estos ejemplos usan un origen de datos System.Collections.Generic.IEnumerable<T>. Los orígenes de datos basados en System.Linq.IQueryProvider usanSystem.Linq.IQueryable<T> orígenes de datos y árboles de expresión . Los árboles de expresión tienen limitaciones en la sintaxis de C# permitida. Además, cada origen de datos IQueryProvider
, como EF Core puede imponer más restricciones. Compruebe la documentación del origen de datos.
La mayoría de estos métodos funcionan en secuencias, donde una secuencia es un objeto cuyo tipo implementa la IEnumerable<T> interfaz o la IQueryable<T> interfaz. Los operadores de consulta estándar proporcionan funcionalidades de consulta, como el filtrado, la proyección, la agregación, la ordenación y mucho más. Los métodos que componen cada conjunto son miembros estáticos de las Enumerable clases y Queryable , respectivamente. Se definen como métodos de extensión del tipo en el que operan.
La distinción entre IEnumerable<T> y IQueryable<T> determina cómo se ejecuta la consulta en tiempo de ejecución.
Para IEnumerable<T>
, el objeto enumerable devuelto captura los argumentos que se pasaron al método . Cuando se enumera ese objeto, se emplea la lógica del operador de consulta y se devuelven los resultados de la consulta.
Para IQueryable<T>
, la consulta se traduce en un árbol de expresiones. El árbol de expresiones se puede traducir a una consulta nativa cuando el origen de datos puede optimizar la consulta. Bibliotecas como Entity Framework traducen consultas LINQ en consultas SQL nativas que se ejecutan en la base de datos.
En el ejemplo de código siguiente se muestra cómo se pueden usar los operadores de consulta estándar para obtener información sobre una secuencia.
string sentence = "the quick brown fox jumps over the lazy dog";
// Split the string into individual words to create a collection.
string[] words = sentence.Split(' ');
// Using query expression syntax.
var query = from word in words
group word.ToUpper() by word.Length into gr
orderby gr.Key
select new { Length = gr.Key, Words = gr };
// Using method-based query syntax.
var query2 = words.
GroupBy(w => w.Length, w => w.ToUpper()).
Select(g => new { Length = g.Key, Words = g }).
OrderBy(o => o.Length);
foreach (var obj in query)
{
Console.WriteLine($"Words of length {obj.Length}:");
foreach (string word in obj.Words)
Console.WriteLine(word);
}
// This code example produces the following output:
//
// Words of length 3:
// THE
// FOX
// THE
// DOG
// Words of length 4:
// OVER
// LAZY
// Words of length 5:
// QUICK
// BROWN
// JUMPS
Siempre que sea posible, las consultas de esta sección usan una secuencia de palabras o números como origen de entrada. En el caso de las consultas en las que se emplean relaciones más complicadas entre objetos, los siguientes orígenes que modelan una escuela se utilizan:
public enum GradeLevel
{
FirstYear = 1,
SecondYear,
ThirdYear,
FourthYear
};
public class Student
{
public required string FirstName { get; init; }
public required string LastName { get; init; }
public required int ID { get; init; }
public required GradeLevel Year { get; init; }
public required List<int> Scores { get; init; }
public required int DepartmentID { get; init; }
}
public class Teacher
{
public required string First { get; init; }
public required string Last { get; init; }
public required int ID { get; init; }
public required string City { get; init; }
}
public class Department
{
public required string Name { get; init; }
public int ID { get; init; }
public required int TeacherID { get; init; }
}
Cada Student
tiene un nivel académico, un departamento principal y una serie de puntuaciones. Un Teacher
también tiene una propiedad City
que identifica el campus donde el profesor imparte clases. Un Department
tiene un nombre y una referencia a un Teacher
que actúa como jefe del departamento.
Puede encontrar el conjunto de datos en el repositorio de origen.
Tipos de operadores de consulta
Los operadores de consulta estándar difieren en el tiempo de ejecución, en función de si devuelven un valor singleton o una secuencia de valores. Esos métodos que devuelven un valor singleton (como Average y Sum) se ejecutan inmediatamente. Métodos que devuelven una secuencia aplazan la ejecución de la consulta y devuelven un objeto enumerable. Puede usar la secuencia de salida de una consulta como secuencia de entrada en otra consulta. Las llamadas a métodos de consulta se pueden encadenar juntas en una consulta, lo que permite que las consultas se vuelvan arbitrariamente complejas.
Operadores de consulta
En una consulta LINQ, el primer paso es especificar el origen de datos. En una consulta LINQ, la from
cláusula viene primero para introducir el origen de datos (students
) y la variable de intervalo (student
).
//queryAllStudents is an IEnumerable<Student>
var queryAllStudents = from student in students
select student;
La variable de intervalo es similar a la variable de iteración en un foreach
bucle, excepto que no se produce ninguna iteración real en una expresión de consulta. Cuando se ejecuta la consulta, la variable de intervalo actúa como referencia a cada elemento sucesivo de students
. Dado que el compilador puede deducir el tipo de student
, no es necesario especificarlo explícitamente. Puede introducir más variables de intervalo en una let
cláusula . Para obtener más información, vea let (Cláusula).
Nota:
Para orígenes de datos no genéricos como ArrayList, la variable de intervalo debe escribirse explícitamente. Para más información, consulte el procedimiento para consultar un objeto ArrayList con LINQ (C#) y Cláusula from.
Una vez obtenido un origen de datos, puede realizar cualquier número de operaciones en ese origen de datos:
-
Filtre los datos mediante la
where
palabra clave . -
Ordenar datos mediante las
orderby
palabras clave y opcionalmentedescending
. -
Agrupar datos mediante las
group
palabras clave y opcionalmenteinto
. -
Combinar datos mediante la
join
palabra clave . -
Datos del proyecto mediante la
select
palabra clave .
Tabla de sintaxis de expresiones de consulta
En la tabla siguiente se enumeran los operadores de consulta estándar que tienen cláusulas de expresión de consulta equivalentes.
Transformaciones de datos con LINQ
Language-Integrated Consulta (LINQ) no solo trata de recuperar datos. También es una herramienta eficaz para transformar datos. Mediante una consulta LINQ, puede usar una secuencia de origen como entrada y modificarla de muchas maneras para crear una nueva secuencia de salida. Puede modificar la propia secuencia sin modificar los propios elementos mediante la ordenación y la agrupación. Pero quizás la característica más eficaz de las consultas LINQ es la capacidad de crear nuevos tipos. La cláusula select crea un elemento de salida a partir de un elemento de entrada. Se usa para transformar un elemento de entrada en un elemento de salida:
- Combine varias secuencias de entrada en una sola secuencia de salida que tenga un nuevo tipo.
- Cree secuencias de salida cuyos elementos constan de solo una o varias propiedades de cada elemento de la secuencia de origen.
- Cree secuencias de salida cuyos elementos constan de los resultados de las operaciones realizadas en los datos de origen.
- Cree secuencias de salida en un formato diferente. Por ejemplo, puede transformar datos de filas SQL o archivos de texto en XML.
Estas transformaciones se pueden combinar de varias maneras en la misma consulta. Además, la secuencia de salida de una consulta se puede usar como secuencia de entrada para una nueva consulta. En el ejemplo siguiente se transforman los objetos de una estructura de datos en memoria en elementos XML.
// Create the query.
var studentsToXML = new XElement("Root",
from student in students
let scores = string.Join(",", student.Scores)
select new XElement("student",
new XElement("First", student.FirstName),
new XElement("Last", student.LastName),
new XElement("Scores", scores)
) // end "student"
); // end "Root"
// Execute the query.
Console.WriteLine(studentsToXML);
El código genera la siguiente salida XML:
<Root>
<student>
<First>Svetlana</First>
<Last>Omelchenko</Last>
<Scores>97,90,73,54</Scores>
</student>
<student>
<First>Claire</First>
<Last>O'Donnell</Last>
<Scores>56,78,95,95</Scores>
</student>
...
<student>
<First>Max</First>
<Last>Lindgren</Last>
<Scores>86,88,96,63</Scores>
</student>
<student>
<First>Arina</First>
<Last>Ivanova</Last>
<Scores>93,63,70,80</Scores>
</student>
</Root>
Para obtener más información, vea Crear árboles XML en C# (LINQ to XML).
Puede usar los resultados de una consulta como origen de datos para una consulta posterior. En este ejemplo se muestra cómo ordenar los resultados de una operación de combinación. Esta consulta crea una combinación agrupada y luego ordena los grupos según el elemento categoría, que todavía está en el ámbito. Dentro del inicializador de tipos anónimos, una subconsulta ordena todos los elementos coincidentes de la secuencia de productos.
var orderedQuery = from department in departments
join student in students on department.ID equals student.DepartmentID into studentGroup
orderby department.Name
select new
{
DepartmentName = department.Name,
Students = from student in studentGroup
orderby student.LastName
select student
};
foreach (var departmentList in orderedQuery)
{
Console.WriteLine(departmentList.DepartmentName);
foreach (var student in departmentList.Students)
{
Console.WriteLine($" {student.LastName,-10} {student.FirstName,-10}");
}
}
/* Output:
Chemistry
Balzan Josephine
Fakhouri Fadi
Popov Innocenty
Seleznyova Sofiya
Vella Carmen
Economics
Adams Terry
Adaobi Izuchukwu
Berggren Jeanette
Garcia Cesar
Ifeoma Nwanneka
Jamuike Ifeanacho
Larsson Naima
Svensson Noel
Ugomma Ifunanya
Engineering
Axelsson Erik
Berg Veronika
Engström Nancy
Hicks Cassie
Keever Bruce
Micallef Nicholas
Mortensen Sven
Nilsson Erna
Tucker Michael
Yermolayeva Anna
English
Andersson Sarah
Feng Hanying
Ivanova Arina
Jakobsson Jesper
Jensen Christiane
Johansson Mark
Kolpakova Nadezhda
Omelchenko Svetlana
Urquhart Donald
Mathematics
Frost Gaby
Garcia Hugo
Hedlund Anna
Kovaleva Katerina
Lindgren Max
Maslova Evgeniya
Olsson Ruth
Sammut Maria
Sazonova Anastasiya
Physics
Åkesson Sami
Edwards Amy E.
Falzon John
Garcia Debra
Hansson Sanna
Mattsson Martina
Richardson Don
Zabokritski Eugene
*/
La consulta equivalente mediante la sintaxis del método se muestra en el código siguiente:
var orderedQuery = departments
.GroupJoin(students, department => department.ID, student => student.DepartmentID,
(department, studentGroup) => new
{
DepartmentName = department.Name,
Students = studentGroup.OrderBy(student => student.LastName)
})
.OrderBy(department => department.DepartmentName);
foreach (var departmentList in orderedQuery)
{
Console.WriteLine(departmentList.DepartmentName);
foreach (var student in departmentList.Students)
{
Console.WriteLine($" {student.LastName,-10} {student.FirstName,-10}");
}
}
Aunque puede usarse una cláusula orderby
con una o varias de las secuencias de origen antes de la asociación, normalmente no se recomienda. Es posible que algunos proveedores LINQ no conserven ese orden después de la combinación. Para obtener más información, vea join (Cláusula, Referencia de C#).