410 likes | 715 Views
Высокоуровневые методы информатики и программирования Лекция 16 Встроенный язык запросов. План работы. Введение в язык LINQ LINQ to Object Интерфейс IEnumerable <T> Примеры в Visual Studio Отличие от SQL. Постановка задачи.
E N D
Высокоуровневые методы информатики и программированияЛекция 16Встроенный язык запросов
План работы • Введение в язык LINQ • LINQ to Object • Интерфейс IEnumerable<T> • Примеры в Visual Studio • Отличие от SQL
Постановка задачи • В программе часто требуется выполнять выборки объектов из различных источников данных • находить элементы, которые удовлетворяют некоторым условиям, • Упорядочивать элементы, • формировать на новые объекты используя существующие. • Существует много типов источников данных, которые хранят множества объектов: • массивы; • коллекции (нетипизированные и типизированные); • XML документы; • базы данных. • Оказалось, что можно единообразно решать эти задачи для всех этих типов источников данных. • С этой целью в языке C# был разработан новый язык: Language INtegratedQuery - LINQ.
LINQ - Language INtegrated Query • Новая возможность языка C# 3.0; • Запросы к источникам данных являются частью языка C#; • Стандартные операции запросов - StandardQueryOperators API; • Единый язык запросов к коллекциям в памяти, XML документам и базам данных.
LINQ позволяет • создавать и выполнять единообразные запросы (query expressions) для работы с • любыми объектами, которые реализуют интерфейсIEnumerable<T> (непосредственно или через расширяющие методы); • реляционными базами данных; • объектами DataSets (которые хранят данные из БД); • XML документами.
Разновидности LINQ • LINQ toObjects– для выполнения запросов к структурам данных в оперативной памяти (System.Linq). • LINQ to SQL (DLinq) –для выполнения запросов к реляционным БД. Выполняет трансляцию LINQ запросов к объектной модели в запросы SQL и посылает их к базе данных для выполнения. После возврата результатов от БД, LINQ to SQL транслирует их назад в объекты, с которыми может работать. • LINQ toEntities – способ выполнения запросов к БД с помощью описания соответствия между классами программы и логической моделью баз данных. • LINQ toDataSet – для выполнения запросов к выборке из БД в оперативной памяти – DataSet (отсоединенной режим работы с БД). • LINQ to XML (XLinq) – для выполнения запросов к XML документам. Дает возможность искать коллекции элементов и атрибутов. Аналогичен XPath и XQuery. (System.Xml.Linq)
Преимущества LINQ • Единообразный способ запроса к данным. • Единый синтаксис для изучения и запоминания. • Строго типизированные запросы - ошибки определяются уже при компиляции. • Работает подсказка IntelliSense в Visual Studio.
Технология LINQ toObjects • Для выполнения запросов к структурам данных в оперативной памяти. Можно делать запросы к любому типу данных, который поддерживает интерфейс IEnumerable<T> (C#) • Пространство имен System.Linq.
Интерфейс IEnumerable<T> • Все обобщенные коллекции поддерживают этот интерфейс. • Большинство StandardQueryOperators являются расширяющими методами в статическом классе System.Linq.Enumerable и содержат первый параметр с типом IEnumerable<T>. • Для получения доступа к StandardQueryOperators необходимо добавить namespace System.Linq (содержится в DLL System.Core.dll, подключается автоматически). • Последовательность это любая коллекция, которая поддерживает данный интерфейс.
Общий вид LINQ запроса var <результат> = from <объектколлекции>in <коллекция> where <условие> orderby <ключ> select <объект резутьтата>;
Операции LINQ запроса • Для записи запросов можно использовать следующие ключевые слова.
Грамматика выражении запросов (Query Expressions) При составлении выражений запросов необходимо следовать следующим правилам: • Запрос должен начинаться с ключевого слова from. • Основная часть запроса может включать несколько ключевых слов from или where. • Слово from это генератор, который объявляет одну или более переменную перечисления, которые пробегают по элементам последовательности или объединения нескольких последовательностей. • Слово where фильтрует элементы последовательности или объединения нескольких последовательностей в результирующую последовательность. • Затем может идти слово orderby, которое содержит одно или несколько полей сортировки с возможностью указания направления сортировки (по увеличению или уменьшению значения поля). • Затем должны следовать слова select или group. • В конце запроса может быть продолжение. В продолжении м.б. • слово into(направляет результаты запроса в воображаемую последовательность вывода, которое работает как слово from для части запроса, начинающейся со слов в пункте 2), • или несколько слов join, • или другая повторяющаяся последовательность этих пронумерованных пунктов, начиная со слов в пункте № 2.
Методы выборки LINQ Для результатов выборки можно выполнить различные методы: и многие другие
Пример с массивом Задача: выбрать из целочисленного массива все числа меньше 5 и упорядочить их. int[] numbers = { 5, 4, 1, 3, 9, 8, 6, 7, 2, 0 }; varlowNums = from n in numberswhere n < 5 orderby n select n; Console.WriteLine(“LINQ: Numbers < 5:"); foreach (var x in lowNums) { Console.WriteLine(x); } Свой алгоритм C помощью LINQ int[] arr = { 5, 4, 1, 3, 9, 8, 6, 7, 2, 0 }; int[] arr1 = new int[10]; intkol = 0; for (int i = 0; i < arr.Length; i++) { if (arr[i] < 5){ arr1[kol] = arr[i]; kol++; } } Array.Sort(arr1,0,kol); Console.WriteLine("Simple: Numbers < 5:"); for (int i=0;i<kol; i++) { Console.WriteLine(arr1 [i]); }
Пример • Запрос к массиву int[] numbers = { 10, 20, 30, 40, 1, 2, 3, 8 }; // Only print items less than 10. IEnumerable<int> subset = from i in numbers where i < 10 orderbyi descending select i; foreach (inti in subset) Console.WriteLine("Item: {0}", i); • Использование var int[] numbers = {10, 20, 30, 40, 1, 2, 3, 8}; // Use implicit typing here... var subset = from i in numbers where i < 10 orderbyi descending select i; // ...and here. foreach (vari in subset) Console.WriteLine("Item: {0} ", i);
Анонимные типы public class Customer { public string Name; public Address Address; public string Phone; public List<Order> Orders; … } public class Contact { public string Name; public string Phone; } class ??? { public string Name; public string Phone; } Customer c = GetCustomer(…); Contact x = new Contact { Name = c.Name, Phone = c.Phone }; Customer c = GetCustomer(…); var x = new { Name = c.Name, Phone = c.Phone }; Создание анонимного типа с инициализацией Customer c = GetCustomer(…); var x = new { c.Name, c.Phone };
LINQ стиль программирования class Contact { … }; List<Contact> contacts = new List<Contacts>(); foreach(Customer c in customers) { if(c.State == “WA”) { Contact ct = new Contact(); ct.Name = c.Name; ct.Phone = c.Phone; contacts.Add(ct); } } var contacts = from c in customers where c.State == "WA" select new { c.Name, c.Phone };
Преобразование выборки в коллекции • Результат выборки можно преобразовать в коллекции с помощью методов • ToArray<T>(), • ToDictionary<TSource,TKey>(), • ToList<T>(). • Например: int[] numbers = { 10, 20, 30, 40, 1, 2, 3, 8 }; // Получить результат выборки в виде массива int[]. int[] subsetAsIntArray = (from i in numbers where i < 10 select i).ToArray<int>(); // Получить результат выборки в видеколлекции List<int>. List<int> subsetAsListOfInts = (from i in numbers where i < 10 select i).ToList<int>();
Пример преобразования var numbers = new int[] { 1, 4, 9, 16, 25, 36 }; List<int> numQuery2 = (from num in numbers where (num % 2) == 0 select num).ToList();// or like this: // numQuery3 is still an int[] var numQuery3 = (from num in numbers where (num % 2) == 0 select num).ToArray();
Пример с объектами класса // Создаем массив объектов car. car[ ] arrayOfCars = new car[6] { new car("Ford",1992), new car("Fiat",1988), new car("Buick",1932), new car("Ford",1932), new car("Dodge",1999), new car("Honda",1977) }; var cars = from cr in arrayOfCars where (cr.Year<1960) select cr; foreach (var с in cars) { Console.WriteLine("{0} – {1}", c.Make,c.Year); } public class car { // конструктор public car(string make,int year) { Make=make; Year=year; } // свойства public int Year { get;set ;} public string Make { get;set;} }
LINQ и обобщенные коллекции • Пример простого класса: class Car { public string Nomer = string.Empty; public string Color = string.Empty; public int Speed; public string Make = string.Empty; } • Создание коллекции static void Main(string[] args) { // Создаем обобщенную коллекцию объектов Car – List<Car> List<Car> myCars = new List<Car>() { new Car{Nomer = "в562ва", Color = "Silver", Speed = 160, Make = "BMW"}, new Car{Nomer = "p123то", Color = "Tan", Speed = 140, Make = "BMW"}, new Car{Nomer = "c345ке", Color = "Black", Speed = 220, Make = "VW"}, new Car{Nomer = "в654нс", Color = "Rust", Speed = 180, Make = "Yugo"}, new Car{Nomer = "с162ми", Color = "White", Speed = 250, Make = "Ford"} }; }
Запрос к обобщенной коллекции // Create a query expression. var fastCars = from c in myCars where c.Speed > 200 select c; foreach (var car in fastCars) Console.WriteLine("{0} ездит слишком быстро!", car.Nomer);
Построение запросов • Общий вид запроса varresult = from item in container select item; varallCars = from c in myCars select c; varnomers = from c in myCars select c.Nomer; var makes = (from c in myCars select c.Make).Distinct<string>(); • Запрос с условием varresult = from item in container where Boolean expression select item; varonlyBMWs = from c in myCars where c.Make == "BMW" select c; varonlyFastBMWs = from c in myCars where c.Make == "BMW" && c.Speed >= 100 select c; • Создание объектов нового типа varresult = from item in container select new {…} varmakesColors = from c in myCars select new {c.Make, c.Color}; • Сортировка результатов varresult = from item in container orderby valueascending/descending select item; var subset = from c in myCarsorderbyc.Nomer select c; var subset = from c in myCars where c.Speed > 55 orderbyc.PetName descending select c;
Преобразование над IEnumerable<T> • Преобразование в другие типы -Reverse<>(), ToArray<>(), ToList<>(), и др. • Извлечени некоторых элементов - Distinct<>(), Union<>(), Intersect<>() и др. • Выполнение операций над элементами - Count<>(), Sum<>(), Min<>(), Max<>()и др.
Определение количества элементов // Определяем количество элементов выборки int numb = (from g in currentVideoGames where g.Length > 6orderby gselect g).Count<string>();
Определение различий static void GetDiff() { List<string> myCars = new List<String> { "Yugo", "Aztec", "BMW"}; List<string> yourCars = new List<String> { "BMW", "Saab", "Aztec" }; varcarDiff =(from c in myCars select c) .Except(from c2 in yourCars select c2); Console.WriteLine("Here is what you don't have, but I do:"); foreach (string s in carDiff) Console.WriteLine(s); // Prints Yugo. }
Классы Customer и Order public class Order { public intOrderID { get ; set;} public intItemID { get; set; } public string CustomerID { get; set; } public DateTimeOrderDate { get; set; } public override string ToString() { return string.Format("OrderID:{0} \r\nOrderName: {1} OrderDate: {2}", OrderID, OrderName, OrderDate); } } public class Customer { public string CustomerID { get; set; } public string Name { get; set; } public string City { get; set; } public override string ToString() { return CustomerID + "\t" + City; } }
Класс Item public class Item { public intItemID {get;set;} public string ItemName {get;set;} public string Category { get; set; } public decimal UnitPrice {get; set; } public intUnitsInStock {get; set; } public override string ToString() { return string.Format("ItemID : {0} \r\nItemName: {1} \r\n " + "Category: {2} \r\nUnitPrice: {3} \r\nUnitsInStock: {4}", ItemID, ItemName, Category, UnitPrice, UnitsInStock); } }
Коллекция заказчиков List<Customer>cust = new List<Customer> { new Customer { CustomerID = "ALFKI", City = "Берлин", Name = "Франс Майер"}, new Customer { CustomerID = "BONAP", City = "Париж", Name = "Поль Франсе" }, new Customer { CustomerID = "CONSH", City = "Лондон", Name = "Джон Кенеди"}, new Customer { CustomerID = "EASTC", City = "Лондон", Name = "Иван Петров" }, new Customer { CustomerID = "FRANS", City = "Торонто", Name = "Петр Сидоров" }, new Customer { CustomerID = "LONEP", City = "Мюнхен", Name = "Борис Байер" }, new Customer { CustomerID = "NORTS", City = "Лондон", Name = "ЕленаГрин" }, new Customer { CustomerID = "THEBI", City = "Мюнхен", Name = "Фриц Гендер" } };
Коллекция товаров itemList List<Item> itemList = new List<Item> { new Item { ItemID = 1, ItemName = "Энциклопедия", Category="Знание", UnitPrice = 55.99M, UnitsInStock = 39 }, new Item { ItemID = 2, ItemName = "Тренажер", Category="Спорт", UnitPrice = 75.00M, UnitsInStock = 17 }, new Item { ItemID = 3, ItemName = "Кородка для CD“, Category="Хранилище", UnitPrice = 4.99M, UnitsInStock = 13 }, new Item { ItemID = 4, ItemName = "Томатный кетчуп", Category="Продукты", UnitPrice = 0.56M, UnitsInStock = 53 }, new Item { ItemID = 5, ItemName = "Плеер IPod", Category="Развлечение", UnitPrice = 220.99M, UnitsInStock = 0 }, new Item { ItemID = 6, ItemName = "Война и мир CD", Category="Развлечение", UnitPrice = 7.99M,UnitsInStock = 120 }, new Item { ItemID = 7, ItemName = "Война миров DVD", Category="Развлечение", UnitPrice = 6.99M, UnitsInStock = 15 }, new Item { ItemID = 8, ItemName = "Клюквенный соус", Category=“Продукты", UnitPrice = 0.89M, UnitsInStock = 6 }, new Item { ItemID = 9, ItemName = "Диетический рис", Category="Продукты", UnitPrice = 13.00M, UnitsInStock = 29 }, new Item { ItemID = 10, ItemName = “Виноград", Category="Продукты", UnitPrice = 1.19M, UnitsInStock = 4 } }
Коллекция заказов orderList List<Order> orderList = new List<Order> { new Order { OrderID = 1, ItemID = 2, CustomerID = "BONAP", OrderDate = DateTime.Now }, new Order { OrderID = 2, ItemID = 5, CustomerID= "FRANS", OrderDate = DateTime.Now }, new Order { OrderID = 3, ItemID = 7, CustomerID = "CONSH ", OrderDate = DateTime.Now }, new Order { OrderID = 4, ItemID = 9, CustomerID = "FRANS", OrderDate = DateTime.Now }, new Order { OrderID = 5, ItemID = 10, CustomerID = "FRANS", OrderDate = DateTime.Now } };
Простые запросы // получение всех потребителей живущих в Лондоне var results = from c in cust where c.City == "Лондон" select c; foreach (var c in results1)Console.WriteLine(c); // получение всех потребителей упорядоченных по названию города и имени var results = from с in cust orderbyc.City, c.Name select new {c.City, c.Name}
// получение всех товаров дороже 10 и упорядочение по увеличению цены varSelOrder = (from a in itemList where (a.UnitPrice > 10M) orderbya.UnitPrice select a); foreach (var obj in SelOrder) Console.WriteLine("ItemName = {0}, UnitPrice = {1}", obj.ItemName, obj.UnitPrice); // получение всех товаров дороже 10 и упорядочение по уменьшению цены SelOrder = (from a in itemList where (a.UnitPrice > 10M) orderbya.UnitPrice descending select a); foreach (var obj in SelOrder) Console.WriteLine("ItemName = {0}, UnitPrice = {1}", obj.ItemName, obj.UnitPrice); // получение двух товаров дороже 10 и упорядочение по уменьшению цены, // без самого дорогого товара var SelOrder2 = (from a in itemList where (a.UnitPrice > 10M) orderbya.UnitPrice descending select a).Skip(1).Take(2); foreach (var obj in SelOrder2) Console.WriteLine("ItemName = {0}, Price = {1}", obj.ItemName,obj.UnitPrice);
Связывание источников данных и создание нового класса varitemOrders = from i in itemList join o inorderListoni.ItemIDequalso.ItemID select new { i.ItemName, CustomerID}
Отложенное выполнение • Выборка не формируется до тех пор, пока она не будет использоваться Пример: int[] numbers = {10,20,30,40,1,2,3,8 }; // описываем выражения для получаем числа // меньше чем 10. var subset = from i in numbers where i < 10 select i; // выражение LINQ выполняется здесь! foreach (var i in subset) Console.WriteLine("{0} < 10", i); Console.WriteLine(); // Меняем некоторые данные в массиве. numbers[0] = 4; // Опять оцениваем выражение. foreach (var j in subset) Console.WriteLine("{0} < 10", j);
Соответствие языков LINQ и SQL • Языки LINQ и SQL имеют много общего • Язык LINQ (интегрированный язык) var query = from element in collection [, from element2 in collection2] where condition orderby orderExpression [ascending|descending] [, orderExpression2 ...] select [alias = ]columnExpression[,[alias2 = ]columnExpression2] • Язык SQL (язык реляционныхбаз данных) SELECT [Element.ColumnExpression[, Element2.ColumnExpression2] FROM Collection AS Element[, Collection2 AS Element2] WHERE Condition ORDER BY OrderExpression [ASCENDING|DESCENDING][, OrderExpression2 ...]
Примеры запросов SQL и LINQ • SQL запрос к БД SELECT * from Books WHERE QuatityInStock > 50 AND Price > 50.00 • LINQ запрос к коллекции объектов var result = from b inBooks where b.QuatityInStock > 50 && Price > 50.00 select b;
Простой LINQ запрос кбазе данных SQL Server using System; using System.Linq; using System.Data.Linq; using nwind; // // создаем объект для доступа к БД Northwind Northwind db = new Northwind(@"Data Source=.\SQLEXPRESS;Initial Catalog=Northwind"); // LINQ запрос к таблице Customer в объекте db varcusts = from c in db.Customers where c.City == "Rio de Janeiro" select c; // вывод полученных результатов foreach (varcust in custs) Console.WriteLine("{0}", cust.CompanyName);