C# 3.0

advertisement
Роман Здебский
Microsoft
rzdebski@microsoft.com
http://blogs.msdn.com/roman





Зачем нужен LINQ? – проблематика и
постановка задачи
Основные идеи LINQ
Сценарии использования
Влияние LINQ на .NET языки
программирования
Демонстрации
Проблема:
Data != Objects
T/SQL
USE Northwind
SELECT ProductName,UnitPrice,
UnitsInStock
FROM products
WHERE productID<3
COMPUTE
SUM(UnitPrice),SUM(UnitsInStock)
ProductName
-------------Chai
Chang
UnitPrice
-----------18,00
19,00
UnitsInStock
-------------39
17
sum
sum
--------------------- ----------37,00
56
(3 row(s) affected)
Oracle SQL*Plus
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} ...
{expr|column|alias|REPORT|ROW} ...]
ON

Должен знать и периодически
использовать:





Relational Algebra
T/SQL (SQL Server)
API (ADO, OLE DB)
XQuery
…
DataSet DS=new DataSet();
XQueryNavigatorCollection oXQ = new XQueryNavigatorCollection();
SqlConnection nwindConn = new SqlConnection("Data
string strXML = "";
Source=localhost;Integrated
Security=SSPI;Initial
string fileName1="c:\\Test\\T1.xml";
Catalog=northwind");
string alias1 = "MyDataTest.xml";
SqlCommand
catCMD
= );
oXQ.AddNavigator(
fileName1,
alias1
string strQuery = "<NewDataSet> { " +
nwindConn.CreateCommand();
" let $bbcatCMD.CommandText
:= document(\"MyDataTest.xml\")/*/*
" + CategoryID,
= "SELECT
" let $cc :=
document(\"MyDatattt.xml\")/*/*
"+
CategoryName
FROM
Categories“;
" for $c in
$cc " +
nwindConn.Open();
" for $b in $bb " +
SqlDataReader myReader =
" where $c/kod = $b/kod " +
catCMD.ExecuteReader();
" return <Table> { $b/nazv,$b/dat,$c/naim } </Table> " +
while (myReader.Read())
" }</NewDataSet>
“;
{
XQueryExpression
xExpression = new XQueryExpression(strQuery);
Dim xmldoc As New
strXML = xExpression.Execute(oXQ).ToXml();
Console.WriteLine("\t{0}\t{1}",
System.Xml.XPath.XPathDocument("c:\books.xml")
StringReader
strReader
=
new
myReader.GetInt32(0), myReader.GetString(1));
DimStringReader(strXML);
nav As System.Xml.XPath.XPathNavigator =
XmlTextReader
reader = newxmldoc.CreateNavigator()
XmlTextReader(strReader);
}
DS.ReadXml(reader);
Dim expr As System.Xml.XPath.XPathExpression =
myReader.Close();
nav.Compile( "//Publisher[. =
DataGrid1.DataSource = DS.Tables[0];
nwindConn.Close();
'MSPress']/parent::node()/Title" )
DataGrid1.DataBind();

Как сделать эффективный paging списка
на web странице?

ASP NET 1.x - AllowPaging property - True
ASP NET 2.0 - Enable Paging option from the
GridView's smart tag

А если список большой… ???

SQL Server 2005:
USE Northwind
SELECT RowNum, EmployeeID, LastName, FirstName
FROM
(SELECT EmployeeID, LastName, FirstName, ROW_NUMBER() OVER(ORDER BY
LastName,FirstName) as RowNum
FROM Employees )
USE Northwind
as EmployeeInfo
SELECT top (@pagesize) EmployeeID, LastName,
WHERE RowNum
FirstName
BETWEEN 1 and 5
SQL Server 2000:
FROM
(
SELECT TOP (@pagesize*@pagenum)
EmployeeID, LastName, FirstName
FROM Employees
ORDER BY LastName DESC, FirstName DESC
)
as EmployeeInfo
ORDER BY LastName ASC, FirstName ASC
Language Integrated Query
Сделать возможности запросов
неотъемлемой частью .NET
языков
Запрашивать, объединять,
трансформировать:





реляционные данные
XML
Объекты
Коллекции и списки
… - в развитии идеи - ВСЁ
C# 3.0
VB 9.0
Others…
.NET Language Integrated Query
LINQ to
Objects
LINQ to
DataSets
LINQ to
SQL
LINQ to
Entities
LINQ to
XML
<book>
<title/>
<author/>
<year/>
<price/>
</book>
Objects
Relational
XML
Version = Assembly references + compilers
Не создается новый CLR runtime
.NET Fx 3.5
.NET Fx 3.0
.NET Fx 3.0
Update
.NET Fx 2.0
.NET Fx 2.0
Minor Update
.NET Fx 2.0
Minor Update
Whidbey
Vista
Orcas
time
List<City> locations = GetLocations();
IEnumerable<City> places =
Name=Kazan
Name=Tver
Name=London
from city in locations
where city.DistanceFromSeattle > 1000
orderby city.Country, city.Name
select city;
Country=Russia DistanceFromSPB=2000
Country=Russia DistanceFromSPB=1100
Country=UK
DistanceFromSPB=4000
Extension methods
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});
Формат запроса
var citiesSPB = from city in locations
where city.DistanceFromSPB > 1000
orderby city.Country, city.Name
select new { city.Name, city.Country };
Фактический порядок выполнения
запроса
Intellisence
Уже используется (XQuery)
Execution plan
for $act in doc("hamlet.xml")//ACT
let $speakers := distinctvalues($act//SPEAKER)
return …
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>







Implicitly typed local variables
Anonymous types
Extension methods
Lambda expressions
Object initializers
Query expressions
Expression trees
Local variable
type inference
Query
var contacts =
expressions
from c in customers
where c.State == "WA"
select new { c.Name, c.Phone };
Lambda
expressions
var contacts =
customers
.Where(c => c.State == "WA")
.Select(c => new { c.Name, c.Phone });
Extension
methods
Anonymous
types
Object
initializers
Local variable
type inference
Dim contacts =
From c In customers _
Where c.State = "WA“ _
Select c.Name, c.Phone
Query
expressions
Lambda
expressions
Dim contacts = _
customers _
.Where(Function (c) c.State = "WA")_
.Select(Function(c) New With { c.Name, c.Phone }
Extension
methods
Anonymous
types
Object
initializers
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.String
ConsoleApplication1.City



Необходимость трансформации или
модификации данных полученных от
запроса
LINQ позволяет осуществлять “data
shaping” с помощью проекций
Удобно использовать с анонимными
типами “anonymous type”,
поддерживаемыми компилятором
<>f__AnonymousType0`2[System.Int32,System.String]
Extension
method
namespace MyStuff
{
public static class Extensions
{
public static string Concatenate(this IEnumerable<string> strings,
string separator) {…}
}
}
Brings extensions
into scope
using MyStuff;
string[] names = new string[] { "Axel", "Mia", "Niels" };
string s = names.Concatenate(", ");
IntelliSense!
obj.Foo(x, y)

XXX.Foo(obj, x, y)
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
public class Product
{
public string Name;
public decimal Price;
}
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; }
}
}
private string □;
public class Product
{
public string Name { get; set; }
public decimal Price { get; set; }
}
public string Name {
get { return □; }
set { □ = value; }
}
Must have both
get and set
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
Must implement
IEnumerable
Must have public
Add method
List<int> numbers = new List<int> { 1, 10, 100 };
List<int> numbers = new List<int>();
numbers.Add(1);
numbers.Add(10);
numbers.Add(100);
Add can take
more than one
parameter
Dictionary<int, string> spellings = new Dictionary<int, string> {
{ 0, "Zero" }, { 1, "One" }, { 2, "Two" }, { 3, "Three" } };
C# 2.0
IEnumerable<Customer> locals =
EnumerableExtensions.Where(customers, delegate(Customer c)
{
return c.ZipCode == 98112;
});
C# 3.0 Lambda выражение
locals.Where(c => c == 98112);
Func<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 )
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);
Source implements
IEnumerable<T>
Source implements
IQueryable<T>
System.Query.Enumerable
Based on Delegates
Objects
System.Query.Queryable
Based on Expression Trees
SQL
DataSets
Others…
Customer[] custs = SampleData.GetCustomers();
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);
string[] names = query.ToArray();
custs
ID
names
Name
Phone
Where
c => c.City == "London"
Select
c => c.Name
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);
}
}
Allen
Arthur
Arthur
Будьте осторожны с отложенным
выполнением запросов и изменением
данных
// Don't do this! NullReferenceException
foreach (var phone in contacts.Descendants("phone"))
{
phone.Remove();
}
foreach (var phone in contacts.Descendants("phone").ToList())
{
phone.Remove();
}
Accessing 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
Accessing data with LINQ
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 };
Classes
describe data
Tables are like
collections
Strongly typed
connections
Integrated
query syntax
Strongly typed
results
Database
DataContext
Table
Class
View
Class
Column
Field / Property
Relationship
Field / Property
Stored Procedure
Method
from c in db.Customers
where c.City == "London"
select c.CompanyName
LINQ Query
Application
Objects
db.Customers.Add(c1);
c2.City = “Seattle";
db.Customers.Remove(c3);
SubmitChanges()
LINQ to SQL
SQL Query
Rows
DML or SProcs
INSERT INTO Cust …
UPDATE Cust …
DELETE FROM Cust …
SELECT CompanyName
FROM Cust
WHERE City = 'London'
SQL Server

Интегрированный в язык доступ к данным



Соответствия (Mapping)




Связывает таблицы и записи с классами и объектами
Построен поверх ADO.NET и .NET Transactions
Определяются атрибутами или во внешнем XML файле
Отношения (relations) соответствуют свойствам (Свойство
Products у Category и Category у Product)
Возможность отложенной или одновременной загрузки
данных через отношения (relations)
Сохраняемость (Persistence)


Автоматическое отслеживание изменений
Обновление через SQL или stored procedures
Add
NorthwindDataContext db = new NorthwindDataContext();
Supplier supplier = new Supplier{CompanyName = “ABC”};
db.Suppliers.Add(supplier);
db.SubmitChanges();

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();
}

Встроенный в C# и VB синтаксис
запросов

SQL-подобные запросы по любым .NET
collection (Все реализующие
IEnumerable)

Мощный язык запросов

Результаты LINQ запросов легко
использовать в DataBinding
Программирование 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); <contacts>
<contact>
}
<name>Great Lakes Food</name>
<phone>(503) 555-7123</phone>
doc.AppendChild(contacts);
</contact>
…
</contacts>
Imperative
model
Document
centric
No integrated
queries
Memory
intensive
Программирование XML с LINQ
Declarative
model
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)
)
);
Element
centric
Integrated
queries
Smaller and
faster
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");

Language integrated query для XML



Мощь выражений XPath / XQuery
Но на C# или VB как языках
программирования
Использует опыт работы с DOM


Element centric, не document centric
Быстрее и компактнее
XName
XNamespace
XText
XNode
XComment
XDeclaration
XContainer
XDocument
XElement
XAttribute
XDocumentType
XStreamingElement
XProcessingInstruction
Часть 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.

Подходы к распараллеливанию:



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);

Language Integrated Query для .NET


LINQ to Objects



Инфраструктура запросов к реляционным данным
LINQ to XML


SQL-like запросы к любым .NET коллекциям
LINQ to SQL


Встроенный в C# 3.0 и VB 9.0 синтаксис запросов
Компактный, быстрый XML DOM с поддержкой
запросов
LINQ to Entities
LINQ to Datasets

Унифицированный подход к запросам и
трансформации объектов, реляционных
данных и XML

Мощь запросов SQL и XQuery встроенная в
C# и VB

Проверка типов, IntelliSense, refactoring
запросов

Модель расширения для других языков
программирования и APIs










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



Для большого числа типовых задач LINQ
освобождает от необходимости тратить
время на написание запросов
Оптимизация запросов и индексирования – по
прежнему профессиональная и нужная
задача
Каждый может более фокусно заниматься
тем, что ему интереснее и в чем он видит
свое профессиональное развитие и интерес
Зона «Спроси Эксперта»
14:00 – 15:00
Роман Здебский
Microsoft
rzdebski@microsoft.com
http://blogs.msdn.com/roman
Download