Transformaciones de datos con LINQ (C#)
Language-Integrated Query (LINQ) no trata simplemente de la recuperación de datos. También es una herramienta eficaz para transformarlos. Mediante una consulta LINQ, puede utilizar 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 elementos con operaciones de ordenación y agrupación. Sin embargo, la característica más eficaz de las consultas LINQ quizás sea la posibilidad de crear nuevos tipos. Esto se logra en la cláusula select. Por ejemplo, puede realizar las tareas siguientes:
Combinar varias secuencias de entrada en una sola secuencia de salida que tiene un tipo nuevo.
Crear secuencias de salida cuyos elementos estén formados por una o varias propiedades de cada elemento de la secuencia de origen.
Crear secuencias de salida cuyos elementos estén formados por los resultados de operaciones realizadas en los datos de origen.
Crear secuencias de salida en un formato diferente. Por ejemplo, puede transformar datos de filas SQL o archivos de texto en XML.
Éstos son sólo algunos ejemplos. De hecho, estas transformaciones se pueden combinar de varias maneras en la misma consulta. Además, la secuencia de salida de una consulta se puede utilizar como secuencia de entrada para una nueva consulta.
Combinar varias entradas en una sola secuencia de salida
Puede utilizar una consulta LINQ para crear una secuencia de salida que contenga elementos de más de una secuencia de entrada. En el ejemplo siguiente se muestra cómo combinar dos estructuras de datos en memoria, pero se pueden aplicar los mismos principios para combinar datos de orígenes XML, SQL o de conjunto de datos. Supongamos que tenemos los dos tipos de clases siguientes:
class Student
{
public string First { get; set; }
public string Last {get; set;}
public int ID { get; set; }
public string Street { get; set; }
public string City { get; set; }
public List<int> Scores;
}
class Teacher
{
public string First { get; set; }
public string Last { get; set; }
public int ID { get; set; }
public string City { get; set; }
}
En el ejemplo siguiente se muestra la consulta:
class DataTransformations
{
static void Main()
{
// Create the first data source.
List<Student> students = new List<Student>()
{
new Student {First="Svetlana",
Last="Omelchenko",
ID=111,
Street="123 Main Street",
City="Seattle",
Scores= new List<int> {97, 92, 81, 60}},
new Student {First="Claire",
Last="O’Donnell",
ID=112,
Street="124 Main Street",
City="Redmond",
Scores= new List<int> {75, 84, 91, 39}},
new Student {First="Sven",
Last="Mortensen",
ID=113,
Street="125 Main Street",
City="Lake City",
Scores= new List<int> {88, 94, 65, 91}},
};
// Create the second data source.
List<Teacher> teachers = new List<Teacher>()
{
new Teacher {First="Ann", Last="Beebe", ID=945, City = "Seattle"},
new Teacher {First="Alex", Last="Robinson", ID=956, City = "Redmond"},
new Teacher {First="Michiyo", Last="Sato", ID=972, City = "Tacoma"}
};
// Create the query.
var peopleInSeattle = (from student in students
where student.City == "Seattle"
select student.Last)
.Concat(from teacher in teachers
where teacher.City == "Seattle"
select teacher.Last);
Console.WriteLine("The following students and teachers live in Seattle:");
// Execute the query.
foreach (var person in peopleInSeattle)
{
Console.WriteLine(person);
}
Console.WriteLine("Press any key to exit.");
Console.ReadKey();
}
}
/* Output:
The following students and teachers live in Seattle:
Omelchenko
Beebe
*/
Para obtener más información, consulte join (Cláusula, Referencia de C#) y select (Cláusula, Referencia de C#).
Seleccionar un subconjunto de cada elemento de origen
Principalmente existen dos maneras de seleccionar un subconjunto de cada elemento de la secuencia de origen:
Para seleccionar un solo miembro del elemento de origen, utilice la operación con punto. En el ejemplo siguiente, supongamos que un objeto Customer contiene varias propiedades públicas que incluyen una cadena denominada City. Cuando se ejecuta, esta consulta generará una secuencia de salida de cadenas.
var query = from cust in Customers select cust.City;
Para crear elementos que contienen más de una propiedad del elemento de origen, puede utilizar un inicializador de objeto con un objeto con nombre o un tipo anónimo. En el ejemplo siguiente se muestra el uso de un tipo anónimo para encapsular dos propiedades de cada elemento Customer:
var query = from cust in Customer select new {Name = cust.Name, City = cust.City};
Para obtener más información, consulte Inicializadores de objeto y de colección (Guía de programación de C#) y Tipos anónimos (Guía de programación de C#).
Transformar objetos en memoria en XML
Las consultas LINQ hacen que sea fácil transformar los datos entre estructuras de datos en memoria, bases de datos SQL, conjuntos de datos ADO.NET y documentos o secuencias XML. En el ejemplo siguiente se transforman los objetos de una estructura de datos en memoria en elementos XML.
class XMLTransform
{
static void Main()
{
// Create the data source by using a collection initializer.
List<Student> students = new List<Student>()
{
new Student {First="Svetlana", Last="Omelchenko", ID=111, Scores = new List<int>{97, 92, 81, 60}},
new Student {First="Claire", Last="O’Donnell", ID=112, Scores = new List<int>{75, 84, 91, 39}},
new Student {First="Sven", Last="Mortensen", ID=113, Scores = new List<int>{88, 94, 65, 91}},
};
// Create the query.
var studentsToXML = new XElement("Root",
from student in students
let x = String.Format("{0},{1},{2},{3}", student.Scores[0],
student.Scores[1], student.Scores[2], student.Scores[3])
select new XElement("student",
new XElement("First", student.First),
new XElement("Last", student.Last),
new XElement("Scores", x)
) // end "student"
); // end "Root"
// Execute the query.
Console.WriteLine(studentsToXML);
// Keep the console open in debug mode.
Console.WriteLine("Press any key to exit.");
Console.ReadKey();
}
}
El código genera el siguiente resultado XML:
< Root>
<student>
<First>Svetlana</First>
<Last>Omelchenko</Last>
<Scores>97,92,81,60</Scores>
</student>
<student>
<First>Claire</First>
<Last>O'Donnell</Last>
<Scores>75,84,91,39</Scores>
</student>
<student>
<First>Sven</First>
<Last>Mortensen</Last>
<Scores>88,94,65,91</Scores>
</student>
</Root>
Para obtener más información, vea Crear árboles XML en C# (LINQ to XML).
Realizar operaciones con elementos de origen
Es posible que una secuencia de salida no contenga elementos o propiedades de elemento de la secuencia de origen. Por el contrario, la salida podría ser una secuencia de valores que se calcula utilizando los elementos de origen como argumentos de entrada. Cuando se ejecuta la siguiente consulta simple, genera una secuencia de cadenas cuyos valores representan un cálculo basado en la secuencia de origen de elementos de tipo double.
Nota
No se permite llamar a métodos en las expresiones de consulta si la consulta se va a convertir en otro dominio. Por ejemplo, no puede llamar a un método normal de C# en LINQ to SQL porque SQL Server no tiene contexto para el mismo. Sin embargo, puede asignar procedimientos almacenados a los métodos y después llamar a los primeros. Para obtener más información, consulte Procedimientos almacenados (LINQ to SQL).
class FormatQuery
{
static void Main()
{
// Data source.
double[] radii = { 1, 2, 3 };
// Query.
IEnumerable<string> query =
from rad in radii
select String.Format("Area = {0}", (rad * rad) * 3.14);
// Query execution.
foreach (string s in query)
Console.WriteLine(s);
// Keep the console open in debug mode.
Console.WriteLine("Press any key to exit.");
Console.ReadKey();
}
}
/* Output:
Area = 3.14
Area = 12.56
Area = 28.26
*/
Vea también
Tareas
Cómo: Combinar datos con LINQ usando cláusulas Join (Visual Basic)
Referencia
select (Cláusula, Referencia de C#)
Conceptos
Expresiones de consultas LINQ (Guía de programación de C#)