Преобразования данных с помощью LINQ (C#)
LINQ используется не только для извлечения данных. Это также мощное средство для преобразования данных. С помощью запроса LINQ можно использовать исходную последовательность в качестве входных данных и изменять ее различными способами для создания новой выходной последовательности. Можно изменить последовательность сама без изменения элементов сами, сортировка и группирование. Однако при необходимости наиболее запросов LINQ предусмотрена удобная возможность создания новых типов. Это выполняется в предложении select. Например, можно выполнить следующие задачи.
Объединить несколько входных последовательностей в одну выходную последовательность, которая имеет новый тип.
Создать выходные последовательности, элементы которых состоят только из одного или нескольких свойств каждого элемента в исходной последовательности.
Создать выходные последовательности, элементы которых состоят из результатов операций, выполняемых над исходными данными.
Создать выходные последовательности в другом формате. Например, можно преобразовать данные из строк SQL или текстовых файлов в XML.
Это только несколько примеров. Разумеется, эти преобразования могут объединяться различными способами в одном запросе. Более того, выходные последовательности одного запроса могут использоваться как входные последовательности для нового запроса.
Соединение нескольких входных последовательностей в одну выходную
Запрос LINQ можно использовать для создания выходной последовательности, содержащей элементы из нескольких входных последовательностей. В следующем примере показано объединение двух находящихся в памяти структур данных, но те же принципы могут применяться для соединения данных из источников XML, SQL или DataSet. Предположим, что существуют два следующих типа классов.
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; }
}
В следующем примере показан запрос.
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
*/
Дополнительные сведения см. в разделах Предложение join (Справочник по C#) и Предложение "select" (справочник по C#).
Выбор подмножества каждого исходного элемента
Существует два основных способа выбора подмножества каждого элемента в исходной последовательности.
Чтобы выбрать только один член исходного элемента, используйте операцию dot. В следующем примере предполагается, что объект Customer содержит несколько открытых свойств, включая строку с именем City. При выполнении этот запрос создаст выходную последовательность строк.
var query = from cust in Customers select cust.City;
Для создания элементов, содержащих более одного свойства исходного элемента, можно использовать инициализатор объектов либо с именованным объектом, либо с анонимным типом. В следующем примере показано использование анонимного типа для инкапсуляции двух свойств из каждого элемента Customer.
var query = from cust in Customer select new {Name = cust.Name, City = cust.City};
Дополнительные сведения см. в разделах Инициализаторы объектов и коллекций (Руководство по программированию в C#) и Анонимные типы (Руководство по программированию в C#).
Преобразование находящихся в памяти объектов в XML
Запросы LINQ упрощают преобразования данных между структурами данных в памяти, базами данных SQL, наборами данных ADO.NET и потоками или документами XML. В следующем примере объекты в находящейся в памяти структуре данных преобразуются в XML-элементы.
class XMLTransform
{
static void Main()
{
// Create the data source by using a collection initializer.
// The Student class was defined previously in this topic.
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();
}
}
Код формирует следующие выходные 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>
Дополнительные сведения см. в разделе Создание XML-деревьев в C# (LINQ to XML).
Выполнение операций над исходными элементами
Выходная последовательность может не содержать какие-либо элементы или свойства элементов из исходной последовательности. Результатом может быть последовательность значений, вычисляемых с использованием исходных элементов в качестве входных аргументов. При выполнении следующего простого запроса выводится последовательность строк, значения которых рассчитаны на основе исходной последовательности элементов типа double.
Примечание
Вызов методов в выражениях запроса не поддерживается, если запрос будет перенесен в какой-либо другой домен.Например, невозможно вызвать обычный C# метод в LINQ to SQL, так как в SQL Server для него отсутствует контекст.Тем не менее, хранимые процедуры можно сопоставить методам и вызывать последние.Дополнительные сведения см. в разделе Хранимые процедуры [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
*/
См. также
Задачи
Ссылки
Предложение "select" (справочник по C#)
Основные понятия
Выражения запросов LINQ (Руководство по программированию на C#)