Роман Здебский microsoft [email protected]
TRANSCRIPT
Интегрированные в язык запросы (LINQ) в Microsoft Visual Studio 2008
Роман ЗдебскийMicrosoft
[email protected] http://blogs.msdn.com/roman
Содержание
Зачем нужен LINQ? – проблематика и постановка задачи
Основные идеи LINQ Сценарии использования Влияние LINQ на .NET языки
программирования Демонстрации
Проблема:Data != Objects
Отголоски старого единого мира
T/SQL
Oracle SQL*Plus
USE NorthwindSELECT ProductName,UnitPrice, UnitsInStockFROM productsWHERE productID<3 COMPUTE SUM(UnitPrice),SUM(UnitsInStock)
REPF[OOTER] [PAGE] [printspec [text|variable] ...] | [OFF|ON]REPH[EADER] [PAGE] [printspec [text|variable] ...] | [OFF|ON]COMP[UTE] [function [LAB[EL] text] ... OF {expr|column|alias} ... ON {expr|column|alias|REPORT|ROW} ...]
ProductName UnitPrice UnitsInStock-------------- ------------ --------------Chai 18,00 39Chang 19,00 17
sum sum--------------------- -----------37,00 56
(3 row(s) affected)
Разработчик data-driven приложений на C# или VB
Должен знать и периодически использовать: Relational Algebra T/SQL (SQL Server) API (ADO, OLE DB) XQuery …
Нетипизированные островаSqlConnection nwindConn = new SqlConnection("Data Source=localhost;Integrated Security=SSPI;Initial Catalog=northwind"); SqlCommand catCMD = nwindConn.CreateCommand(); catCMD.CommandText = "SELECT CategoryID, CategoryName FROM Categories“; nwindConn.Open(); SqlDataReader myReader = catCMD.ExecuteReader(); while (myReader.Read()) { Console.WriteLine("\t{0}\t{1}", myReader.GetInt32(0), myReader.GetString(1)); } myReader.Close(); nwindConn.Close();
DataSet DS=new DataSet();XQueryNavigatorCollection oXQ = new XQueryNavigatorCollection();string strXML = "";string fileName1="c:\\Test\\T1.xml";string alias1 = "MyDataTest.xml";oXQ.AddNavigator( fileName1, alias1 );string strQuery = "<NewDataSet> { " +" let $bb := document(\"MyDataTest.xml\")/*/* " +" let $cc := document(\"MyDatattt.xml\")/*/* " +" for $c in $cc " +" for $b in $bb " +" where $c/kod = $b/kod " +" return <Table> { $b/nazv,$b/dat,$c/naim } </Table> " +" }</NewDataSet> “ ;XQueryExpression xExpression = new XQueryExpression(strQuery);strXML = xExpression.Execute(oXQ).ToXml();StringReader strReader = new StringReader(strXML);XmlTextReader reader = new XmlTextReader(strReader);DS.ReadXml(reader);DataGrid1.DataSource = DS.Tables[0];DataGrid1.DataBind();
Dim xmldoc As New System.Xml.XPath.XPathDocument("c:\books.xml") Dim nav As System.Xml.XPath.XPathNavigator = xmldoc.CreateNavigator()Dim expr As System.Xml.XPath.XPathExpression = nav.Compile( "//Publisher[. = 'MSPress']/parent::node()/Title" )
Как собеседовали разработчиков data-driven приложений? Как сделать эффективный paging
списка на web странице? ASP NET 1.x - AllowPaging property -
True ASP NET 2.0 - Enable Paging option from
the GridView's smart tag
А если список большой… ???
Custom Paging
USE NorthwindSELECT RowNum, EmployeeID, LastName, FirstNameFROM (SELECT EmployeeID, LastName, FirstName, ROW_NUMBER() OVER(ORDER BY
LastName,FirstName) as RowNum FROM Employees ) as EmployeeInfoWHERE RowNum BETWEEN 1 and 5
SQL Server 2005:
SQL Server 2000:
USE NorthwindSELECT top (@pagesize) EmployeeID, LastName, FirstNameFROM (SELECT TOP (@pagesize*@pagenum) EmployeeID, LastName, FirstNameFROM Employees ORDER BY LastName DESC, FirstName DESC) as EmployeeInfoORDER BY LastName ASC, FirstName ASC
Стоит ли игра свеч?
LINQ
Language Integrated Query
Основная идея проекта LINQ
Сделать возможности запросов неотъемлемой частью .NET языков
Запрашивать, объединять, трансформировать:
реляционные данные XML Объекты Коллекции и списки … - в развитии идеи - ВСЁ
The LINQ Project
Objects
<book> <title/> <author/> <year/> <price/></book>
XML
.NET Language Integrated Query
C# 3.0 VB 9.0 Others…
Relational
LINQ toObjects
LINQ toSQL
LINQ toXML
LINQ toEntities
LINQ toDataSets
.NET Fx 2.0 .NET Fx 2.0Minor Update
.NET Fx 2.0Minor Update
.NET Fx 3.0.NET Fx 3.0
Update
.NET Fx 3.5
Whidbey Vista Orcas
time
Version = Assembly references + compilersНе создается новый CLR runtime
Framework Multitargeting
Linq запросList<City> locations = GetLocations();
IEnumerable<City> places = from city in locations where city.DistanceFromSeattle > 1000 orderby city.Country, city.Name select city;
Name=Kazan Country=Russia DistanceFromSPB=2000Name=Tver Country=Russia DistanceFromSPB=1100Name=London Country=UK DistanceFromSPB=4000
Два альтернативных способа записи запросаExtension methods
Формат запроса
var citiesSPB = from city in locations where city.DistanceFromSPB > 1000 orderby city.Country, city.Name select new { city.Name, city.Country };
var citiesSPB2 = locations.Where(c => c.DistanceFromSPB > 1000).OrderBy(c => c.Name).OrderBy(c => c.Country).Select( c => new {Name= c.Name, Country = c.Country});
ДЕМОНСТРАЦИЯ
Почему Select в конце?Фактический порядок выполнения запросаIntellisenceУже используется (XQuery)
Execution plan
for $act in doc("hamlet.xml")//ACT let $speakers := distinct-values($act//SPEAKER) return …
LINQ возможностиRestriction Where
Projection Select, SelectMany
Ordering OrderBy, ThenBy
Grouping GroupBy
Joins Join, GroupJoin
Quantifiers Any, All
Partitioning Take, Skip, TakeWhile, SkipWhile
Sets Distinct, Union, Intersect, Except
Elements First, Last, Single, ElementAt
Aggregation Count, Sum, Min, Max, Average
Conversion ToArray, ToList, ToDictionary
Casting OfType<T>, Cast<T>
C# 3.0 в Visual Studio 2008
Implicitly typed local variables Anonymous types Extension methods Lambda expressions Object initializers Query expressions Expression trees
C# 3.0
var contacts = from c in customers where c.State == "WA" select new { c.Name, c.Phone };
var contacts = customers .Where(c => c.State == "WA") .Select(c => new { c.Name, c.Phone });
Extension methods
Lambda expressions
Query expressions
Object initializersAnonymous
types
Local variable type
inference
VB 9
Dim contacts = From c In customers _ Where c.State = "WA“ _ Select c.Name, c.Phone
Dim contacts = _ customers _ .Where(Function (c) c.State = "WA")_ .Select(Function(c) New With { c.Name, c.Phone })
Extension methods
Lambda expressions
Query expressions
Object initializers
Anonymous types
Local variable type
inference
Implicitly typed local variablesНеявно типизированные локальные переменные
var testVal = 2 * 2; var testVal2 = "hello".ToUpper(); var testVal3 = new City(); Console.WriteLine(testVal.GetType()); Console.WriteLine(testVal2.GetType()); Console.WriteLine(testVal3.GetType());System.Int32
System.StringConsoleApplication1.City
Проекции данных
Необходимость трансформации или модификации данных полученных от запроса
LINQ позволяет осуществлять “data shaping” с помощью проекций
Удобно использовать с анонимными типами “anonymous type”, поддерживаемыми компилятором
Anonymous typesАнонимные типы
<>f__AnonymousType0`2[System.Int32,System.String]
Extension MethodsМетоды расширения
namespace MyStuff{ public static class Extensions { public static string Concatenate(this IEnumerable<string> strings, string separator) {…} }}
using MyStuff;
string[] names = new string[] { "Axel", "Mia", "Niels" };string s = names.Concatenate(", ");
Extensionmethod
Brings extensions into scope obj.Foo(x, y)
XXX.Foo(obj, x, y)
IntelliSense!
Extension methods Методы расширенияstatic class StaticExtensionClass { public static int toGoInMiles(this City ct) { return (int)(ct.DistanceFromSPB * 1.61) ; } }City ct = new City { Name = "Bor", Country = "RUS", DistanceFromSPB = 100 };Console.WriteLine(ct.toGoInMiles());
161
Automatic propertiesАвтоматические свойства
public class Product{ public string Name; public decimal Price;}
Automatic properties Автоматические свойства
public class Product{ string name; decimal price;
public string Name { get { return name; } set { name = value; } }
public decimal Price { get { return price; } set { price = value; } }}
Automatic properties
public class Product{ public string Name { get; set; } public decimal Price { get; set; }}
private string □;
public string Name { get { return □; } set { □ = value; }}
Must have both get and set
Object InitializersИнициализаторы объектов
public class Point{ private int x, y;
public int X { get { return x; } set { x = value; } } public int Y { get { return y; } set { y = value; } }}
Point a = new Point { X = 0, Y = 1 };
Point a = new Point();a.X = 0;a.Y = 1;
Field or property assignments
Collection InitializersИнициализаторы коллекций
List<int> numbers = new List<int> { 1, 10, 100 };
Must implement IEnumerable
List<int> numbers = new List<int>();numbers.Add(1);numbers.Add(10);numbers.Add(100);
Must have public Add method
Dictionary<int, string> spellings = new Dictionary<int, string> { { 0, "Zero" }, { 1, "One" }, { 2, "Two" }, { 3, "Three" } };
Add can take more than one parameter
Lambda выражения
IEnumerable<Customer> locals = EnumerableExtensions.Where(customers, delegate(Customer c) { return c.ZipCode == 98112; });
C# 2.0
C# 3.0 Lambda выражение
locals.Where(c => c == 98112);
Expression TreesFunc<int, bool> nonExprLambda = x => (x & 1) == 0;Expression<Func<int, bool>> exprLambda = x => (x & 1) ==
0; ParameterExpression xParam = Expression.Parameter(typeof(int), "x"); Expression<Func<int, bool>> exprLambda = Expression.Lambda<Func<int, bool>>(
Expression.Equal( Expression.And(xParam, Expression.Constant(1)), Expression.Constant(0)),
xParam); Console.WriteLine(exprLambda);
x => ( ( x & 1 ) = 0 )
LINQ Архитектура
System.Query.EnumerableBased on Delegates
Source implementsIEnumerable<T>
var query = from c in customers where c.State == "WA" select c.Name;
var query = customers.Where(c => c.State == "WA").Select(c => c.Name);
System.Query.QueryableBased on Expression Trees
Source implementsIQueryable<T>
SQL DataSetsObjects Others…
Отложенное выполнение запросов
Customer[] custs = SampleData.GetCustomers();
custs
PhoneNameID
var query = from c in custs where c.City == "London" select c.Name;
var query = custs.Where(c => c.City == "London").Select(c => c.Name);
Select
c => c.Name
string[] names = query.ToArray();
names
c => c.City == "London"
Where
using System;using System.Query;using System.Collections.Generic; class app { static void Main() { string[] names = { "Allen", "Arthur",
"Bennett" }; IEnumerable<string> ayes = names
.Where(s => s[0] == 'A'); foreach (string item in ayes)
Console.WriteLine(item); names[0] = "Bob"; foreach (string item in ayes)
Console.WriteLine(item); }}
Arthur
using System;using System.Query;using System.Collections.Generic; class app { static void Main() { string[] names = { "Allen", "Arthur",
"Bennett" }; IEnumerable<string> ayes = names
.Where(s => s[0] == 'A'); foreach (string item in ayes)
Console.WriteLine(item); names[0] = "Bob"; foreach (string item in ayes)
Console.WriteLine(item); }}
AllenArthur
Отложенное выполнение запросов
Halloween problemБудьте осторожны с отложенным выполнением запросов и изменением данных
// Don't do this! NullReferenceException foreach (var phone in contacts.Descendants("phone")) { phone.Remove(); }
foreach (var phone in contacts.Descendants("phone").ToList()) { phone.Remove(); }
ДЕМОНСТРАЦИЯ
LINQ to SQLAccessing data today
SqlConnection c = new SqlConnection(…);c.Open();SqlCommand cmd = new SqlCommand( "SELECT c.Name, c.Phone FROM Customers c WHERE c.City = @p0");cmd.Parameters.AddWithValue("@p0", "London“);DataReader dr = c.Execute(cmd);while (dr.Read()) { string name = dr.GetString(0); string phone = dr.GetString(1); DateTime date = dr.GetDateTime(2);}dr.Close();
Queries in quotes
Loosely bound
arguments
Loosely typed result sets
No compile time checks
public class Customer { … }
public class Northwind : DataContext{ public Table<Customer> Customers; …}
Northwind db = new Northwind(…);var contacts = from c in db.Customers where c.City == "London" select new { c.Name, c.Phone };
LINQ to SQLAccessing data with LINQ
Classes describe data
Strongly typed
connections
Integrated query syntax
Strongly typed results
Tables are like collections
LINQ to SQL Mapping
Database
Table
View
Column
Relationship
Stored Procedure
DataContext
Class
Class
Field / Property
Field / Property
Method
LINQ to SQL Архитектура
Application
SQL Server
LINQ to SQL
from c in db.Customerswhere c.City == "London"select c.CompanyName
LINQ Query
SQL Query
SELECT CompanyNameFROM CustWHERE City = 'London'
Rows
Objects SubmitChanges()
DML or SProcs
db.Customers.Add(c1);c2.City = “Seattle";db.Customers.Remove(c3);
INSERT INTO Cust …UPDATE Cust …DELETE FROM Cust …
LINQ to SQL
Интегрированный в язык доступ к данным Связывает таблицы и записи с классами и объектами Построен поверх ADO.NET и .NET Transactions
Соответствия (Mapping) Определяются атрибутами или во внешнем XML
файле Отношения (relations) соответствуют свойствам
(Свойство Products у Category и Category у Product) Возможность отложенной или одновременной
загрузки данных через отношения (relations) Сохраняемость (Persistence)
Автоматическое отслеживание изменений Обновление через SQL или stored procedures
Изменение данных
Update Product product = db.Products.Single(p => p.ProductName== "Chai"); product.UnitsInStock = 11; product.ReorderLevel = 10; product.UnitsOnOrder = 2; db.SubmitChanges();
Delete var supplier = db.Suppliers.FirstOrDefault(s=>s.CompanyName == “ABC"); if ((supplier != null) && (supplier.Products.Count == 0)) { db.Suppliers.Remove(supplier); db.SubmitChanges(); }
NorthwindDataContext db = new NorthwindDataContext(); Supplier supplier = new Supplier{CompanyName = “ABC”}; db.Suppliers.Add(supplier); db.SubmitChanges();
Add
ДЕМОНСТРАЦИЯ
LINQ to Objects
Встроенный в C# и VB синтаксис запросов
SQL-подобные запросы по любым .NET collection (Все реализующие IEnumerable)
Мощный язык запросов
Результаты LINQ запросов легко использовать в DataBinding
LINQ при работе XMLПрограммирование XML сегодня
XmlDocument doc = new XmlDocument();XmlElement contacts = doc.CreateElement("contacts");foreach (Customer c in customers) if (c.Country == "USA") { XmlElement e = doc.CreateElement("contact"); XmlElement name = doc.CreateElement("name"); name.InnerText = c.CompanyName; e.AppendChild(name); XmlElement phone = doc.CreateElement("phone"); phone.InnerText = c.Phone; e.AppendChild(phone); contacts.AppendChild(e); }doc.AppendChild(contacts);
<contacts> <contact> <name>Great Lakes Food</name> <phone>(503) 555-7123</phone> </contact> …</contacts>
Imperativemodel
Documentcentric
No integrated queries
Memory intensive
XDocument loaded = XDocument.Load(@"C:\contacts.xml");contacts var q = from c in loaded.Descendants("contact")
where (int)c.Attribute("contactId") < 4
select (string)c.Element("firstName") + “ “ + (string)c.Element("lastName");
LINQ to XMLПрограммирование XML с LINQ
XElement contacts = new XElement("contacts", from c in customers where c.Country == "USA" select new XElement("contact", new XElement("name", c.CompanyName), new XElement("phone", c.Phone) ));
Declarative model
Elementcentric
Integrated queries
Smaller and faster
LINQ To XML
Language integrated query для XML Мощь выражений XPath / XQuery Но на C# или VB как языках
программирования Использует опыт работы с DOM
Element centric, не document centric Быстрее и компактнее
LINQ to XML objects
XAttributeXNode
XComment XContainer
XDeclaration
XDocument
XDocumentType
XElement
XName
XProcessingInstructionXText
XNamespace XStreamingElement
ДЕМОНСТРАЦИЯ
Parallel Language Integrated Query (PLINQ)Часть ParallelFX LINQ to Objects LINQ to XML Распараллеливание LINQ to SQL – SQL
Server Использование:
Reference System.Concurrency.dll Wrap your data source in an
IParallelEnumerable<T> with a call to the System.Linq.ParallelEnumerable.AsParallel extension method.
Parallel Language Integrated Query (PLINQ)
Подходы к распараллеливанию: pipelined processing stop-and-go processing inverted enumeration
IEnumerable<T> leftData = ..., rightData = ...; var q = from x in leftData.AsParallel() join y in rightData on x.a == y.b select f(x, y);
LINQ Компоненты Language Integrated Query для .NET
Встроенный в C# 3.0 и VB 9.0 синтаксис запросов
LINQ to Objects SQL-like запросы к любым .NET коллекциям
LINQ to SQL Инфраструктура запросов к реляционным
данным LINQ to XML
Компактный, быстрый XML DOM с поддержкой запросов
LINQ to Entities LINQ to Datasets
LINQ Инновации
Унифицированный подход к запросам и трансформации объектов, реляционных данных и XML
Мощь запросов SQL и XQuery встроенная в C# и VB
Проверка типов, IntelliSense, refactoring запросов
Модель расширения для других языков программирования и APIs
Third-Party LINQ Providers LINQ to WebQueries (MSDN Web
sites) LINQ to Amazon (books search) LINQ to RDF Files. LINQ to MySQL LINQ to NHibernate LINQ to LDAP LINQ to Google Desktop LINQ to SharePoint LINQ to Streams (SLinq, Streaming
LINQ) LINQ to Expressions (MetaLinq)
ДЕМОНСТРАЦИЯ
Что бы мы сделали с paging в LINQ?
Ресурсы
Ключевое слово – LINQ Вводим в поиск microsoft.com второй результат – The LINQ
Project
Anders Hejlsberg Chief Designer of C# Architect of LINQ project
Нужно ли забыть T/SQL?
Для большого числа типовых задач LINQ освобождает от необходимости тратить время на написание запросов
Оптимизация запросов и индексирования – по прежнему профессиональная и нужная задача
Каждый может более фокусно заниматься тем, что ему интереснее и в чем он видит свое профессиональное развитие и интерес
Интегрированные в язык запросы (LINQ) в Microsoft Visual Studio 2008
Роман ЗдебскийMicrosoft
[email protected]://blogs.msdn.com/roman
Зона «Спроси Эксперта»14:00 – 15:00