Как разработчики программного обеспечения, мы тратим много времени на извлечение и отображение данных из разных источников. Будь то какой-либо веб-сервис XML или полнофункциональная реляционная база данных, мы были вынуждены изучить различные методы доступа к данным. Не было бы замечательно, если бы метод доступа был одинаковым для всех источников данных? Что ж, нам повезло, потому что с выпуском C # 3.0 и .NET 3.5 Framework, LINQ навсегда изменила игру.
Учебное пособие
- Введение в синтаксис LINQ
- Проекции с использованием LINQ
- Уточнение данных
- Стандартные операторы
Текущий обзор доступа к данным
На платформе .NET мы использовали и используем ADO.NET
для доступа к различным источникам данных. Сообщество open source также предоставило
разработчики с рядом альтернатив.
Language Integrated Query — это новое дополнение к .NET
семья и, как следует из названия, это вид доступа к данным стиля запроса, который
полностью поддерживается языком, чтобы эффективно унифицировать способ доступа к данным
и сделать нашу жизнь проще. LINQ может нацеливаться на ряд различных источников, а именно Oracle,
MSSQL, XML и некоторые другие, но сейчас мы сосредоточимся на самых основных
все, LINQ to Objects.
LINQ to Objects
Обычно для обработки и уточнения данных в наших списках
и различные другие структуры данных, мы использовали цикл «foreach» или другой
тип метода зацикливания, чтобы перебрать объекты и обработать их один за другим
один согласно некоторому условию. Это хорошо, но, честно говоря, это требует много
базовый код, который мы все хотели бы нам не писать. По сути, мы должны были сказать
компилировать каждую деталь процесса, чтобы манипулировать данными.
Именно здесь LINQ сияет лучше всего. Что LINQ позволяет нам
сделать, это просто сказать компилятору, что мы хотели бы выполнить, и позволить компилятору работать
лучший способ добиться этого. Если вы использовали синтаксис SQL раньше, массовые сходства
между LINQ и любым диалектом SQL будет первое, что вы заметите.
Как и SQL, LINQ также поддерживает «select», «from», «where», «join», «group by»
и «упорядочить по» ключевым словам. Вот простой пример запроса списка объектов:
Инициализация списка:
1
2
3
4
5
6
7
8
|
List<Car> ListOfCars = new List<Car>()
{
new Car {name = «Toyota» , owner = «Alex» , model = 1992},
new Car {name = «Mitsubishi», owner = «Jeff» , model = 2005},
new Car {name = «Land Rover», owner = «Danny», model = 2001},
new Car {name = «BMW» , owner = «Danny», model = 2006},
new Car {name = «Subaru» , owner = «Smith», model = 2003}
};
|
Запрос:
1
2
|
IEnumerable<Car> QueryResult = from car in ListOfCars
select car;
|
Первая часть предыдущего кода просто заполняет список
с четырьмя экземплярами класса «Автомобиль». Следующая часть кода, однако, использует
«от» и «выберите» ключевые слова, чтобы выбрать группу объектов. Основное отличие
между SQL и LINQ заключается в том, что ключевое слово «from» ставится перед «select»
ключевое слово, потому что мы должны сначала определить объект, с которым мы хотим работать. в заключение
предложение «select» сообщает компилятору, что мы хотим извлечь в этом запросе. Над
код просто извлекает все, что есть в списке, и присваивает его «QueryResult»
переменная.
Когда мы запрашиваем вещи из объектов (LINQ to Objects), наши
запросы всегда возвращают список объектов IEnumrable <T>. По сути
Тип «IEnumerable» — это вид списка, который предоставляет перечислитель, который
поддерживает простую итерацию над неуниверсальной коллекцией и <T>
тип каждой записи в списке.
Не беспокойтесь, если вы не знакомы с «перечислителями» и «генериками». Только
помните, что результатом запросов LINQ всегда является набор данных
структура, которая позволяет перебирать ее, используя цикл, как показано
ржали:
1
2
|
foreach(Car car in QueryResult)
Console.WriteLine(car.name);
|
Мы узнали, что LINQ всегда возвращает подобную структуру коллекции
в любые другие списки. Тем не менее, запрос LINQ не выполняется, пока его результат
доступ к какой-то другой части кода, например, цикл «foreach» выше. Это к
позволяют нам постоянно определять запрос без накладных расходов путем переоценки
каждый новый шаг в запросе.
Прогнозы
Все идет нормально; но в большинстве случаев наши запросы
быть более сложным; так что давайте попробуем проецировать данные. В SQL проекция означает выбор
имя столбца (-ов) таблицы (-ов), которую желательно видеть появляющейся в результате
запроса. В случае LINQ to Objects выполнение проекции приведет к
в другом типе результата запроса, чем тип объекта, который мы выполняем
запрос на.
Есть два вида проекций, которые мы можем сделать. Мы можем
либо выполнить проекцию на основе существующего типа объекта, либо перейти полностью
Другой способ с использованием анонимных типов. Следующий пример первого
Добрый:
1
2
|
IEnumerable<CarOwner> QueryResult = from car in ListOfCars
select new CarOwner { owner_name = car.owner };
|
В предыдущем коде тип результата запроса объявлен как
<CarOwner>, который отличается от <Car>, тип, с которым инициализируется переменная ListOfCar. У нас есть
также использовал ключевое слово «new» и выполнил несколько заданий внутри фигурных
скобки. В приведенном выше коде использование «select» с ключевым словом «new» говорит
компилятор для создания нового объекта CarOwner для каждой записи в результате запроса.
Также, присваивая значения новому типу, мы инициализировали каждый экземпляр
класса «CarOwner».
Тем не менее, если у вас еще нет типа, определенного для
использовать, вы все еще можете выполнять проекции с использованием анонимных типов.
Проекции с использованием анонимных типов
Было бы много хлопот, если бы для каждой проекции вы были
вынужден создать новый тип. Вот почему, начиная с C # 3.0, поддержка Anonymous
типы были добавлены к языку. Анонимный тип объявляется с использованием «var»
ключевое слово. Он сообщает компилятору, что тип переменной неизвестен до
это назначено в первый раз.
1
2
3
4
5
6
7
8
|
var QueryResult = from car in ListOfCars
select new {
car_name = car.name,
owner_name = car.owner
};
foreach(var entry in QueryResult)
Console.WriteLine(entry.car_name);
|
Выше приведен пример выполнения запроса с помощью Anonymous
типы. Единственное, на что нужно обратить внимание: компилятор не будет
позволяют возвращать анонимные типы из методов.
Доступ к свойствам типа Anonymous очень прост. В Visual Studio 2008 код
Completion / Intellisense также перечисляет свойства, предоставляемые анонимным типом.
Уточнение данных
Обычно, как часть запроса LINQ, нам также необходимо уточнить
результат запроса, указав условие. Как и SQL, LINQ также использует «где»
пункт, чтобы сказать компилятору, какие условия являются приемлемыми.
1
2
3
|
IEnumerable<Car> QueryResult = from car in ListOfCars
where car.name == «Subaru»
select car;
|
Предыдущий код демонстрирует использование предложения where и
условие для подражания. Для дальнейшего определения нескольких условий LINQ поддерживает
конструкции ‘и’ (&&) и ‘или’ (||). Часть «где» в запросе всегда должна быть
Булево выражение, иначе компилятор будет жаловаться.
Сортировать по
При запросе объектов можно полагаться на запрос
цель уже отсортирована. Если это не так, LINQ может позаботиться об этом
с помощью предложения order by, которое обеспечит результат вашего запроса
правильно отсортировано.
1
2
3
|
IEnumerable<Car> QueryResult = from car in ListOfCars
orderby car.model
select car;
|
Если вы запустите приведенный выше код, вы увидите, что результат
запрос отсортирован в порядке возрастания. Вы можете изменить порядок, используя «восходящий» и «нисходящий»
ключевые слова, и далее изменить порядок, указав более одного поля для сортировки
по. Следующий код показывает, как:
1
2
3
|
IEnumerable<Car> QueryResult = from car in ListOfCars
orderby car.model descending
select car;
|
Группировка
LINQ также позволяет группировать результат запроса по значению
конкретное свойство, как показано в этом примере:
1
2
3
|
var QueryResult = from car in ListOfCars
group car by car.owner into carOwnersGroup
select carOwnersGroup.Key;
|
Как видите, LINQ поддерживает предложение «group by» для
указать, по какому объекту и по какому свойству группировать. Ключевое слово «в» будет
затем позвольте нам проецировать на результат группировки, к которому можно получить доступ «Ключом»
свойство.
присоединяется
LINQ поддерживает объединение данных из разных коллекций в один
результат запроса. Вы можете сделать это, используя ключевое слово «join», чтобы указать, какие объекты
присоединиться и использовать ключевое слово «on», чтобы указать соответствие между
два объекта.
Инициализация связанного списка:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
|
List<Car> ListOfCars = new List<Car>()
{
new Car {name = «Mitsubishi», owner = «Jeff» , model = 2005},
new Car {name = «Land Rover», owner = «Danny», model = 2001},
new Car {name = «Subaru» , owner = «Smith», model = 2003},
new Car {name = «Toyota» , owner = «Alex» , model = 1992},
new Car {name = «BMW» , owner = «Danny», model = 2006},
};
List<CarOwner> ListOfCarOwners = new List<CarOwner>()
{
new CarOwner {owner_name = «Danny», age = 22},
new CarOwner {owner_name = «Jeff» , age = 35},
new CarOwner {owner_name = «Smith», age = 19},
new CarOwner {owner_name = «Alex» , age = 40}
};
|
Запрос:
1
2
3
|
var QueryResult = from car in ListOfCars
join carowner in ListOfCarOwners on car.owner equals carowner.owner_name
select new {name = car.name, owner = car.owner, owner_age = carowner.age};
|
В приведенном выше коде, используя анонимный тип, мы присоединились
два объекта в одном результате запроса.
Иерархии объектов с использованием групповых объединений
До сих пор мы узнали, как мы можем использовать LINQ, чтобы построить квартиру
результат запроса списка. С помощью LINQ можно также получить иерархический запрос.
результат использования «GroupJoin». Проще говоря, мы могли бы назначить объекты
свойства каждой записи с запросом LINQ.
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
List<Car> ListOfCars = new List<Car>()
{
new Car {name = «Mitsubishi», owner = «Jeff» , model = 2005},
new Car {name = «Land Rover», owner = «Danny», model = 2001},
new Car {name = «Subaru» , owner = «Smith», model = 2003},
new Car {name = «Toyota» , owner = «Alex» , model = 1992},
new Car {name = «BMW» , owner = «Danny», model = 2006},
};
List<CarOwner> ListOfCarOwners = new List<CarOwner>()
{
new CarOwner {owner_name = «Danny», age = 22},
new CarOwner {owner_name = «Jeff» , age = 35},
new CarOwner {owner_name = «Smith», age = 19},
new CarOwner {owner_name = «Alex» , age = 40}
};
var QueryResult = from carowner in ListOfCarOwners
join car in ListOfCars on carowner.owner_name equals car.owner into carsGroup
select new {name = carowner.owner_name, cars = carsGroup};
foreach(var carOwner in QueryResult)
foreach(var car in carOwner.cars)
Console.WriteLine(«Owner name: {0}, car name: {1}, car model: {2}», carOwner.name, car.name, car.model);
|
В приведенном выше примере за предложением «Join» следует «в»
часть. Это отличается от предыдущей операции соединения, которую мы рассмотрели. Здесь «в»
Предложение используется для группировки автомобилей по владельцу (в carsGroup) и назначения группировки для
«Автомобили» собственность анонимного типа.
Стандартные операторы запросов
Пока что все, что мы видели, было поддержано C # 3.0.
синтаксис. Тем не менее, есть еще большое количество операций, которые C # 3.0 не делает
служба поддержки. Стандартные операторы запросов предоставляют возможности запросов, включая
фильтрация, проекция, агрегация, сортировка и многое другое. Эти операции поэтому поддерживаются
как методы библиотеки LINQ и могут быть выполнены в результате запроса, как показано в
следующий скриншот:
Эти операторы перечислены ниже для вашей справки.
Агрегатные операторы
- Сумма : возвращает сумму всех записей
- Макс : возвращает запись с максимальным значением
- Min : возвращает запись с минимальным значением
- Среднее : возвращает среднее значение для коллекции
- Агрегат : используется для создания индивидуальной агрегации
- LongCount : при работе с большой коллекцией этот метод возвращает значение до максимального значения, поддерживаемого классом «long»
- Count : возвращает «целое число» для количества элементов в коллекции
Элемент Операторы
- Первый : возвращает первую запись из коллекции результатов
- FirstOrDefault : если пустая коллекция, вернет значение по умолчанию, в противном случае вернет первую запись из коллекции
- Single : вернет только элемент из коллекции
- SingleOrDefault : если пустая коллекция, вернет значение по умолчанию, иначе вернет только элемент из коллекции
- Последний : возвращает последнюю запись из коллекции
- LastOrDefault : если пустая коллекция, вернет значение по умолчанию, в противном случае возвращает последнюю запись из коллекции
- ElementAt : возвращает элемент в указанной позиции
- ElementAtOrDefault : если пустая коллекция, вернет значение по умолчанию, в противном случае возвращает элемент в указанной позиции
Установить связанные операторы
- За исключением : аналогично левому соединению в SQL, будут возвращаться записи из одного набора, который не существует в другом наборе
- Союз : возвращает все записи из обоих объектов
- Пересечь : возвращает одинаковые элементы из любого набора
- Distinct : возвращает уникальные записи из коллекции
Операторы генерации
- DefaultIfEmpty : если результат пуст, возвращает значение по умолчанию
- Repeat : повторяется при возврате объектов указанное количество раз
- Пусто : вернет пустую коллекцию IEnumerable
- Диапазон : возвращает диапазон чисел для указанного начального номера и количества
Операторы переработки
- Где : вернет объекты, которые соответствуют указанному условию
- OfType : вернет объекты указанного типа
Операторы преобразования
- ToLookup : возвращает результат как поиск
- ToList : возвращает результат в виде коллекции List
- ToDictionary : возвращает результат в виде словаря
- ToArray : возвращает результат в виде коллекции Array
- AsQueryable : возвращает результат в виде IQueryable <T>
- AsEnumerable : возвращает результат в виде IEnumerable <T>
- OfType : фильтрует коллекцию в соответствии с указанным типом
- Cast : используется для преобразования слабо типизированной коллекции в строго типизированную коллекцию.
Операторы разбиения
- Взять : возвращает указанное количество записей
- Takewhile : возвращает указанное количество записей, в то время как указанное условие оценивается как true
- Пропустить : пропускает указанное количество записей и возвращает остальные
- SkipWhile : пропускает указанное количество записей, в то время как указанное условие оценивается как истинное
Операторы квантификатора
- Any : возвращает true или false для указанного условия
- Содержит : возвращает true или false для существования указанного объекта
- Все : возвращает истину или ложь всем объектам, удовлетворяющим указанному условию
Присоединяйтесь к операторам
- Присоединиться : возвращает записи, в которых ключи в наборах совпадают
- GroupJoin : используется для построения иерархических объектов на основе отношения мастера и детализации
Операторы равенства
- SequenceEqual : возвращает true, если коллекции равны
Операторы сортировки
- Реверс : возвращает старую коллекцию
- ThenBy : используется для дальнейшей сортировки
- ThenByDescending : используется для выполнения дальнейшей сортировки в порядке убывания
- OrderBy : используется для определения порядка
- OrderByDescending : используется для определения нисходящего порядка
Операторы проекции
- SelectMany : используется для выравнивания иерархической коллекции
- Выберите : используется для определения возвращаемых свойств
Операторы конкатенации
- Concat : используется для объединения двух коллекций
И что теперь?
LINQ зарекомендовал себя очень полезным для запросов объектов, а SQL-подобный синтаксис позволяет легко
учиться и использовать. Кроме того, огромное количество стандартных операторов позволяет объединить несколько операторов
выполнять сложные запросы. В продолжение этого урока мы рассмотрим, как можно использовать LINQ для
базы данных запросов и контент XML.
Продаем .NET скрипты и компоненты на CodeCanyon
- Подпишитесь на нас в Твиттере или подпишитесь на ленту Nettuts + RSS для получения лучших учебных материалов по веб-разработке.