LINQ в C#
LINQ (Language INtegrated Query – Язык интегрированных запросов) - это встроенный в C# язык запросов, позволяющий извлекать и обрабатывать данные из различных источников, которые могут иметь различные форматы данных.
LINQ - технология Microsoft, предназначенная для поддержки запросов к данным всех типов на уровне языка. Запросы могут выполняться для массивов и коллекций в памяти, базам данных, документам XML и другим источникам информации.
Ниже перечислены разновидности LINQ.
• LINQ to Objects. Позволяет реализовать запросы LINQ к локальным массивам и коллекциям.
• LINQ to XML. Позволяет реализовать запросы LINQ для манипулирования и опроса документов на языке XML.
• LINQ to SQL. Позволяет реализовать запросы LINQ к «отсоединенным наборам» (не для любых баз данных) и реляционным базам данных, созданных в среде Microsoft SQL Server.
• LINQ to Entities. Позволяет реализовать запросы LINQ внутри среды Entity Framework (EF).
• Parllel LINQ (он же PLINQ). Эта разновидность позволяет выполнять параллельную обработку данных, возвращенных запросом LINQ.
В настоящее время LINQ является неотъемлемой частью библиотек базовых классов .NET и среды разработки Visual Studio.
Работа с базами данных создает специфические проблемы. Не обнаруживаются:
• Неправильные ссылки на поля базы данных.
• Наличие кода (программных модулей) базы данных, который не проверяется во время компиляции,
• Разница между типами базы данных и типами данных в языке, на котором написана программа.
LINQ включает в себя ряд стандартных операций запросов, разделяемых на 2 большие группы - отложенные операции (выполняются не во время инициализации, а только при их вызове) и не отложенные операции (выполняются сразу).
Источниками могут быть как локальные коллекции, так и удаленные базы данных. Для извлечения данных могут применяться достаточно сложные условия поиска и фильтрации для типизированных данных, а мест назначения для извлеченных данных может быть несколько. Одновременно с извлечением можно реализовать арифметические операции, а также сортировку и группировку возвращаемых данных, поэтому язык LINQ позволяет выполнять сложные обработки коллекций.
Запросы могут направляться к источникам данных, для которых реализованы интерфейсы IEnumerable<T> и IQueryable<T>. Интерфейс IEnumerable<T> предназначен для реализации запросов к массивам и находящимся в памяти коллекциям данных, а интерфейс IQueryable<T> позволяет адресовать запросы LINQ к удаленным источникам данных (к базам данных, созданным в среде Microsoft SQL Server). С помощью объекта класса ObjectQuery<T> можно оформить запрос, который возвратит коллекцию типизированных объектов. Запрос может возвращаться также в переменную типа var.
Примечание: интерфейс IEnumerable<T> не может возвращать индекс для коллекций, поскольку применяется хэширование. Простой способ – использовать оператор цикла foreach со счетчиком. Для массивов можно применять операцию IndexOf.
С точки зрения оформления запросов различают:
• Синтаксис запросов.
• Синтаксис методов.
• Смешанный синтаксис.
При синтаксисе запросов применяются ключевые слова языка C#, относящиеся к запросам LINQ. В тексте программы их отличают по синему цвету. При синтаксисе методов ключевые слова, обычно записывают с заглавной буквы и применяют лямбда-выражения. Например, where – синтаксис запросов, Where – синтаксис методов. В смешанном запросе синтаксис методов заключают в круглые скобки, а затем после точки указывают метод синтаксиса запросов. Синтаксис методов распространен более широко по сравнению с синтаксисом запросов.
Ниже приведен пример запроса на выборку из массива четных чисел обоими способами с одновременным упорядочиванием на убывание:
int[ ] lst = { 7, 10, 9, 8, 11, 16};// Исходный массив
// Синтаксис запросов
IEnumerable<int> qry =
from chi in lst
where chi % 2 == 0
orderby chi descending
select chi;
// Синтаксис методов
IEnumerable<int> qry = lst.Where(chi => chi % 2 == 0).OrderByDescending(n => n);
Результат запроса можно вывести с помощью оператора foreach.
foreach (int n in qry)
{
Console.Write(n + " ");
}
Запрос может возвращаться также в переменную типа var. Такая переменная может содержать набор строк из таблицы. Например,
var query = from c in Customers
where c.City == "Москва"
select c.Order;
Ниже приведен пример программы, в которой объявлен и инициализирован массив целых чисел, а затем с помощью запроса из массива выбираются числа, меньшие 16.
static void Main()
{
// Массив целых чисел.
int [ ] Ints = {7, 16, 27, 15, 4, 1, 3, 92, 2 };
// Простой запрос.
var MyQry = // Неявно типизированная переменная
from num in Ints // Переменная диапазона (num) и где искать
where num < 16 // Условие для поиска
select num; // Выполнить запрос
// Просмотр результатов выполнения запроса.
foreach (var n in MyQry)
{
Console.Write( "{0} ", n);
}
Console.ReadKey();
}
Вывод программы имеет вид:
Вместо строки var MyQry = можно записать IEnumerable<int> MyQry=. Результат не изменится, поскольку указанный интерфейс для массивов реализуется автоматически.
Структура запроса содержит
• Имя запроса. Тип для имени задается либо var, либо IEnumerable<T>, либо IQueryable<T> (для баз данных). После имени записывается знак равенства.
• Если список состоит из встроенного типа данных (string, int, double и т. д.), то этот тип данных может быть указан в качестве возвращаемого типа данных.
• Конструкция from → in. После слова from указывается произвольное имя (в примере num, оно задает диапазон просмотра. Слово in задает источник для поиска (в данном случае массив Ints).
• Команда select.
Замечание 1: В конструкции from → in указано, что задается диапазон просмотра. Возможно это неудачная формулировка. Диапазон очень похож на объявленную переменную в операторе цикла foreach.
Замечание 2: Хотя в примере и рассмотрен типовой запрос, на практике можно применять элементы запроса индивидуально, без связи с другими элементами.
Замечание 3: При использовании обобщенного интерфейса IEnumerable<T> требуется указать имя для <T>, это не требуется при указании типа var.
Замечание 4: Многие команды LINQ являются «отложенными» (например, команда select), то есть они выполняются только тогда, когда начинается перечисление результатов (вывод) реализации запроса. Достаточно часто это выполняется с помощью цикла foreach. Поэтому, если запрос был сформулирован неправильно, то ошибка будет обнаружена только при перечислении результатов запроса и будет вызвана исключительная ситуация.
Замечание 5: Команда select (соответственно и метод Select) применима только для объектов, приведенных к типу перечисления.
Примечание: Для формирования последовательнх целых чисел можно воспользоваться функцией Range.
Список аргументов этой функции состоит из двух значений: первый параметр start задает начальной значение последовательности, а второй параметр count задает количество членов последовательности. Ниже представлен пример оформления этой функции:
var seq =Enumerable.Range( 5,10);
foreach (int val in seq) Console.Write(" {0}", val);
Приведенный пример генерирует последовательность (начиная с 5 10 чисел):
Ниже приведен пример программы, которая запрашивает ввод строки целых чисел, преобразует числа, введенные в виде строки, в числовое представление, сортирует их и выводит на экран.
static void Main()
{
Console.WriteLine("Введите целые числа через пробел");
string InStr = Console.ReadLine();
string [ ] MyInts = InStr.Split( );// Расщепление на массив строк
// Преобразование массива строк и сортировка чисел по возрастанию
int [ ] nums = MyInts.Select(x => int.Parse(x)).OrderBy(y => y).ToArray();
foreach (int n in nums)
{
Console.Write("{0} ",n);
}
Console.ReadKey();
}
Пример выполнения программы ниже:
В этом примере применен синтаксис методов, поэтому вместо команды select применен метод Select (с лямбда-выражением). Вместо where можно применять (не в данном примере) метод Where (с лямбда-выражением) и т. д. Эти варианты оформления носят названия синтаксиса запросов и синтаксиса методов. Ниже приведен пример оформления запроса обоими методами.
string[ ] names = {"Андрей", "Сергей", "Иван", "Артем", "Леопольд", "Наталья",
"Оксана", "Федор"};
// Синтаксис методов (отсутствует from), n – произвольное имя
IEnumerable<string> sequence = names
.Where(n => n.Length < 6)
.Select(n => n); // Обратите внимание на точки
// Синтаксис запросов
IEnumerable<string> sequence = from n in names
where n.Length < 6
select n; // Все команды из строчных букв
foreach (string name in sequence)
{
Console.WriteLine("{0}", name);
}
Независимо от выбранного метода будет выведено:
LINQ в C#
Лекции по предмету «Программирование»