una query in linq - torino technologies...

8
http://www.devleap.com http://devcon.devleap.com Pag. 1 www.devleap.it LINQ Introduction Marco Russo [email protected] Cosa è LINQ Nuovo modello di programmazione Integrazione delle query nei linguaggi .NET Accesso a dati in formati diversi Grafo di oggetti in memoria Relazionale XML Infoset Fonte dati “esterna” È uno strumento, non un’architettura applicativa Poter mettere una query nel codice non implica Né rinunciare alle architetture n-tier Né cambiare per forza le architetture esistenti Una query in LINQ Una query in LINQ assomiglia a una query SQL var query = from c in Customers where c.Country == "Italy" select c.CompanyName; Ma tutto è tipizzato e controllato dal compilatore I dati si possono leggere con foreach foreach ( string name in query ) { Console.WriteLine( name ); } Una query in LINQ Cosa è Customers? Può essere Un array/collection Un DataSet Una tabella relazionale Un’entità (EDM) Customer[] Customers; DataSet ds = GetDataSet(); DataTable Customers = ds.Tables["Customers"]; DataContext db = new DataContext( ConnectionString ); Table<Customer> Customers = db.GetTable<Customer>(); NorthwindModel dataModel = new NorthwindModel(); ObjectQuery<Customer> Customers = dataModel.Customers; LINQ: schema generale Oggetti <book> <title/> <author/> <year/> <price/> </book> XML Mondo relazionale Come funziona LINQ La query expression viene trasformata in codice “normale” Customer[] Customers = GetCustomers(); var query = from c in Customers where c.Country == "Italy" select c; Customer[] Customers = GetCustomers(); IEnumerable<Customer> query = Customers .Where( c => c.Country == "Italy" ); Local Type Inference Lambda Expression Extension Method

Upload: lammien

Post on 10-Jun-2018

229 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: Una query in LINQ - Torino Technologies Grouptorinotechnologiesgroup.it/Download/LINQIntroduction.pdf•Una query in LINQ assomiglia a una query SQL ... •LINQ to Entities è un ORM

http://www.devleap.com http://devcon.devleap.com Pag. 1

www.devleap.it

LINQ Introduction

Marco Russo

[email protected]

Cosa è LINQ

• Nuovo modello di programmazione

• Integrazione delle query nei linguaggi .NET

• Accesso a dati in formati diversi

• Grafo di oggetti in memoria

• Relazionale

• XML Infoset

• Fonte dati “esterna”

• È uno strumento, non un’architettura applicativa

• Poter mettere una query nel codice non implica

• Né rinunciare alle architetture n-tier

• Né cambiare per forza le architetture esistenti

Una query in LINQ

• Una query in LINQ assomiglia a una query SQL

var query =

from c in Customers

where c.Country == "Italy"

select c.CompanyName;

• Ma tutto è tipizzato e controllato dal compilatore

• I dati si possono leggere con foreach

foreach ( string name in query ) {

Console.WriteLine( name );

}

Una query in LINQ

• Cosa è Customers?

• Può essere

• Un array/collection

• Un DataSet

• Una tabella relazionale

• Un’entità (EDM)

Customer[] Customers;

DataSet ds = GetDataSet();

DataTable Customers = ds.Tables["Customers"];

DataContext db = new DataContext( ConnectionString );

Table<Customer> Customers = db.GetTable<Customer>();

NorthwindModel dataModel = new NorthwindModel();

ObjectQuery<Customer> Customers = dataModel.Customers;

LINQ: schema generale

Oggetti

<book> <title/>

<author/> <year/> <price/>

</book>

XML Mondo

relazionale

Come funziona LINQ

• La query expression viene trasformata in codice “normale”

Customer[] Customers = GetCustomers();

var query =

from c in Customers

where c.Country == "Italy"

select c;

Customer[] Customers = GetCustomers();

IEnumerable<Customer> query =

Customers

.Where( c => c.Country == "Italy" );

Local Type Inference

Lambda Expression

Extension Method

Page 2: Una query in LINQ - Torino Technologies Grouptorinotechnologiesgroup.it/Download/LINQIntroduction.pdf•Una query in LINQ assomiglia a una query SQL ... •LINQ to Entities è un ORM

http://www.devleap.com http://devcon.devleap.com Pag. 2

Come funziona LINQ

• LINQ introduce il concetto di “tuple” attraverso gli anonymous type

var query =

from c in Customers

where c.Country == "Italy"

orderby c.Name

select new { c.Name, c.City };

var query =

Customers

.Where( c => c.Country == "Italy" );

.OrderBy( c => c.Name )

.Select( c => new { c.Name, c.City } );Anonymous Type

Cosa si può fare con LINQ

• Dipende dalle implementazioni di LINQ

• Set di operazioni “standard” predefinito

• Si possono aggiungere operazioni specifiche per singole implementazioni

Query in memoria o remote?

• Entrambe le possibilità

• IEnumerable<T>

• La query è composta da delegate connessi tra loro

• Durante l’iterazione vengono richiamati i delegate

• Le espressioni nella query sono valutate solo durante l’iterazione

• IQueryable<T>

• La query è compilata in un expression tree (il codice è rappresentato come un albero di oggetti)

• Al momento dell’esecuzione, l’expression tree può essere manipolato

• Alla base delle query remote (es. LINQ to SQL)

Cosa NON è LINQ

• Non è una forma di Embedded-SQL

• Non è un Object Relational Mapper

• LINQ to SQL è un ORM “semplice”

• LINQ to Entities è un ORM più “completo

• Non è un modo per spostare il Data Layer nella UI

• Non è solo per l’accesso a database relazionali

• Non è obbligatorio usarlo

• Ma se padroneggiato migliora la qualità della vita

www.devleap.it

Ripasso C# 3.0 per LINQ

Local Type Inference

• Dichiarazione variabile con keyword var

• Tipo inferito dall’espressione dell’initializer

• Indispensabile con tipi anonimi

www.devleap.it

// Esempi di inferenza di tipo

public void ValidUse( decimal d ) {

var x = 2.3; // double

var y = x; // double

var r = x / y; // double

var s = "sample“; // string

var l = s.Length; // int

var w = d; // decimal

var p = default(string); // string

}

// Usi non consentiti

class DemoNotAllowed {

var k = 0;

public void f( var x ) {}

public var g() {

return 2;

}

public void InvalidUseLocal() {

var x;

var y = null;

}

}

Page 3: Una query in LINQ - Torino Technologies Grouptorinotechnologiesgroup.it/Download/LINQIntroduction.pdf•Una query in LINQ assomiglia a una query SQL ... •LINQ to Entities è un ORM

http://www.devleap.com http://devcon.devleap.com Pag. 3

Local Type Inference Best Practices

• Usare per anonymous types, query expressions e tipi generici complessi

www.devleap.it

var c3 = new { Name = "Tom", Age = 31 };

var query = from c in customers where c.Discount > 3 select c;

var ordersByCustomer = new Dictionary<string, List<Orders>>();

• Non consigliabile per risultato di new su tipo

• Non usare per costanti e semplici espressioni

var customer = new Customer();

var numbers = new int[] { 1, 3, 5, 9 };

var x = 5;

var amount = customer.Amount;

var x = y / z;

var count = list.Count();

Sintassi Lambda Expressions

• Anonymous delegate

www.devleap.it

int sum = Aggregate(

l.Values,

( int a, int b ) => { return a + b; } );

int sum = Aggregate(

l.Values,

( a, b ) => { return a + b; } );

int sum = Aggregate(

l.Values,

( a, b ) => a + b );

• Explicitly typed parameter list

• Implicitly typed parameter list

• Expression body

int sum = Aggregate(

l.Values,

delegate( int a, int b ) { return a + b; }

);

Sintassi Lambda Expressions

• Altri casi particolari

• Con un solo parametro si possono evitare le parentesi

• Se non ci sono parametri le parentesi sono obbligatorie

www.devleap.it

( int a, int b ) => { return a + b; } // Explicitly typed, statement body

( int a, int b ) => a + b; // Explicitly typed, expression body

( a, b ) => { return a + b; } // Implicitly typed, statement body

( a, b ) => a + b // Implicitly typed, expression body

( x ) => sum += x // Single parameter with parentheses

x => sum += x // Single parameter no parentheses

() => sum + 1 // No parameters

Lambda Expressions

• Predicate: espressione booleana che indica l’appartenenza di un elemento a un gruppo

• Projection: espressione che restituisce un tipo diverso dal parametro (che è singolo)

// Predicate

( age ) => age > 21

// Projection: takes a string and returns an int

( s ) => s.Length

Lambda Expressions

• Concetto chiave: il parametro è quello del delegate, ma si può accedere alle variabili in scope come in qualsiasi anonymous method

int sum = 0;

int result = AggregateSingle(

l.Values,

x => sum += x

);}

Func<T> per Lambda Expressions

• Lambda expression si può assegnare a variabili di tipo delegate Func<T> definite in System.Linq

• Non è obbligatorio, ma è una convenzione e serve per ottenere expression tree

www.devleap.it

public delegate T Func<T>();

public delegate T Func<A0, T>( A0 arg0 );

public delegate T Func<A0, A1, T> ( A0 arg0, A1 arg1 );

public delegate T Func<A0, A1, A2, T>( A0 arg0, A1 arg1, A2 arg2 );

public delegate T Func<A0, A1, A2, A3, T> ( A0 arg0, A1 arg1, A2 arg2, A3 arg3 );

Page 4: Una query in LINQ - Torino Technologies Grouptorinotechnologiesgroup.it/Download/LINQIntroduction.pdf•Una query in LINQ assomiglia a una query SQL ... •LINQ to Entities è un ORM

http://www.devleap.com http://devcon.devleap.com Pag. 4

Expression Trees

• Assegnazione a Expression<D>

• Definito in System.Linq.Expressions

• Expression tree ottenuto si può compilare con Compile e il risultato è un delegate che può essere eseguito

• Expression Trees sono immutabili

www.devleap.it

Func<int> x = (a, b) => a + b; // Lambda Expression

Int a = x( 29, 13 ); // Invocation

Expression<Func<int>> y = (a, b) => a + b; // Expression Tree

Int b = y.Compile()( 29, 13 ); // Compilation and Invocation

Extension Methods

• Metodi che “apparentemente” estendono una classe senza derivarla

• Costrutto sintattico che usa metodi statici pubblici

• Usare this sul primo parametro

www.devleap.it

static class ExtensionMethods {

public static decimal Double( this decimal d ) { return d + d; }

public static decimal Triple( this decimal d ) { return d * 3; }

public static decimal Increase( this decimal d ) { return d + 1; }

public static decimal Decrease( this decimal d ) { return d – 1; }

public static decimal Half( this decimal d ) { return d / 2; }

}

decimal x = 14M, y = 14M;

x = Half( Triple( Decrease( Decrease( Double( Increase( x ) ) ) ) ) );

y = y.Increase().Double().Decrease().Decrease().Triple().Half();

Object Initialization Expressions

• Inizializzazione di oggetti (value o reference)

• Senza usare un costruttore

• Serve ad avere tutto in un’espressione

www.devleap.it

// Implicitly calls default constructor before object initialization

Customer customer = new Customer { Name = "Marco", Country = "Italy" };

Customer customer = new Customer();

customer.Name = "Marco";

customer.Country = "Italy";

Collection Initializers

• Sintassi di inizializzazione per classi collection

• Chiama metodo Add per ogni elemento nella lista

www.devleap.it

List<Customer> list = new List<Customer> {

new Customer( "Jack", 28 ) { Country = "USA"},

new Customer { Name = "Paolo" },

new Customer { Name = "Marco", Country = "Italy" }

};

List<Customer> list = new List<Customer>();

list.Add( new Customer( "Jack", 28 ) { Country = "USA"} );

list.Add( new Customer { Name = "Paolo" } );

list.Add( new Customer { Name = "Marco", Country = "Italy" } );

Anonymous Types

• Tipi definiti attraverso object initializer senza specificare un nome di classe

• Istanze di anonymous types sono immutabili in C#

• Membri definiti da sintassi assegnazione o nome membro passato

• Stesso tipo se membri hanno

• Stesso nome

• Stesso tipo

• Stesso ordine

www.devleap.it

var c3 = new { Name = "Tom", Age = 31 };

var c4 = new { c2.Name, c2.Age };

var c5 = new { c1.Name, c1.Country };

var c6 = new { c1.Country, c1.Name };

c3 e c4 sono

dello stesso tipo

c5 e c6 sono di

due tipi diversi

www.devleap.it

LINQ Query Syntax

Page 5: Una query in LINQ - Torino Technologies Grouptorinotechnologiesgroup.it/Download/LINQIntroduction.pdf•Una query in LINQ assomiglia a una query SQL ... •LINQ to Entities è un ORM

http://www.devleap.com http://devcon.devleap.com Pag. 5

LINQ Query Syntax

• Estensione sintassi C# 3.0 per usare LINQ

• Estensioni analoghe per Visual Basic 9.0

• Forma semplificata per accedere a operatori definiti con extension method

www.devleap.it

C#

Query Syntax

• from/where/select

from d in developers

where d.Language == "C#"

select d.Name;

developers.Where(

(d) => d.Language == "C#”) .Select( (d) => d.Name);

www.devleap.it

C#

Extension Methods

developers.Where(

(d) => d.Language == "C#"

).Select(

(d) => d.Name

);

Enumerable.Select(

Enumerable.Where(

developers,

(d) => d.Language == "C#" ),

(d) => d.Name

);

www.devleap.it

C#

Risultato di una query

• IEnumerable<T>

• Dove T è il tipo restituito dalla query

• Per i tipi anonimi è obbligatorio l’uso di var

IEnumerable<string> query =

from d in developers

where d.Language == "C#"

select d.Name;

var query =

from d in developers

select new {d.Name, d.Language };

www.devleap.it

Clausola from

• Definisce variabile usata in lambda expression di altri extension method per operatori usati nella query

• Iterazione di variabile per tutti gli elementi del data source specificato

from rangeVariable in dataSource

www.devleap.it

C#

Nested from

• Navigazione in grafo di oggetti con clausole from nidificate

• Più avanti vediamo anche join

var ordersQuery =

from c in customers

from o in c.Orders

select new { c.Name, o.IdOrder, o.EuroAmount };

www.devleap.it

Page 6: Una query in LINQ - Torino Technologies Grouptorinotechnologiesgroup.it/Download/LINQIntroduction.pdf•Una query in LINQ assomiglia a una query SQL ... •LINQ to Entities è un ORM

http://www.devleap.com http://devcon.devleap.com Pag. 6

C#

Clausola where

• Specifica un’espressione di filtro da applicare a ogni elemento iterato nella clausola from

• L’espressione è un delegate – i calcoli vengono ripetuti ogni volta

• Mantenere espressioni semplici

• Evitare calcoli con risultati invarianti

from d in developers

where d.Language == "C#"

www.devleap.it

C#

C#

Clausola group

• Clausola group … by suddivide una sequenza in gruppi

var query = from d in developers

group d by d.Language;

• Risultato gerarchico – richiede due foreach nidificate

foreach (var group in query)

foreach (var item in group)

C#

Clausola orderby

• Specifica ordinamento del risultato

• Si può specificare ascending / descending

var ordersSortedByCustomerAndEuroAmount =

from c in customers

from o in c.Orders

orderby c.Name, o.EuroAmount descending

select new { c.Name, o.IdOrder, o.EuroAmount };

www.devleap.it

C#

Clausola join

• Associa due sequenze in base al valore di un membro che deve avere valore uguale

var categoriesAndProducts =

from c in categories

join p in products on c.IdCategory equals p.IdCategory

select new {

c.IdCategory,

CategoryName = c.Name,

Product = p.Description

}; www.devleap.it

C#

Risultato equivalente a LEFT JOIN

• Si usa DefaultIfEmpty “riappiattendo” il risultato

var categoriesAndProducts =

from c in categories

join p in products on c.IdCategory equals p.IdCategory

into productsByCategory

from pc in productsByCategory.DefaultIfEmpty(

new Product {

IdProduct = String.Empty,

Description = String.Empty,

IdCategory = 0})

select new { c.IdCategory, CategoryName = c.Name,

Product = pc.Description }; www.devleap.it

C#

Clausola let

• La keyword let consente di referenziare più volte la stessa espressione in una query

var categoriesByProductsNumberQuery =

from c in categories

join p in products on c.IdCategory equals p.IdCategory

into productsByCategory

let ProductsCount = productsByCategory.Count()

orderby ProductsCount

select new { c.IdCategory, ProductsCount};

www.devleap.it

Page 7: Una query in LINQ - Torino Technologies Grouptorinotechnologiesgroup.it/Download/LINQIntroduction.pdf•Una query in LINQ assomiglia a una query SQL ... •LINQ to Entities è un ORM

http://www.devleap.com http://devcon.devleap.com Pag. 7

www.devleap.it

LINQ to SQL

Assembly e Namespace

• Assembly

• System.Data.Linq

• Namespace

• System.Data.Linq

• System.Data.Linq.Mapping

www.devleap.it

SQL

C#

Query in LINQ to SQL

• Customers è un tipo in .NET

var query =

from c in Customers

where c.Country == "USA"

&& c.State == "WA"

select new {c.CustomerID, c.CompanyName, c.City };

• Necessario mapping metadati per ottenere SQL:

SELECT CustomerID, CompanyName, City

FROM Customers

WHERE Country = 'USA’ AND Region = 'WA'

www.devleap.it

C#

DataContext

• Rappresenta connessione a database

• Metodo GetTable<T> per ottenere Table<T>

DataContext db = new DataContext("Database=Northwind");

Table<Customer> Customers = db.GetTable<Customer>();

• Classi derivate da DataContext

• Specializzazione per un database particolare

• Contiene dati membri corrispondenti a tabelle

• Istanze di Table<T> dove T descrive una riga

www.devleap.it

C#

Table<T>

• Rappresenta una tabella

• T è il tipo che descrive una riga

• Classe decorata con attributi di mapping

• Table<T> implementa IQueryable<T>

• Istanze di Table<T> usate nelle query LINQ

DataContext db = new DataContext( ConnectionString );

Table<Customer> customers = db.GetTable<Customer>();

var query = from c in customers

where c.Country == "USA” && c.State == "WA"

select new {c.CustomerID, c.CompanyName, c.City };

www.devleap.it

C#

Mapping entità con attributi

• Attributi definiscono mapping entità – tabelle SQL Server

[Table(Name="Customers")]

public class Customer {

[Column] public string CustomerID;

[Column] public string CompanyName;

[Column] public string City;

[Column(Name="Region")] public string State;

[Column] public string Country;

}

www.devleap.it

Page 8: Una query in LINQ - Torino Technologies Grouptorinotechnologiesgroup.it/Download/LINQIntroduction.pdf•Una query in LINQ assomiglia a una query SQL ... •LINQ to Entities è un ORM

http://www.devleap.com http://devcon.devleap.com Pag. 8

C#

Come viene eseguita la query

• Le query LINQ to SQL sono expression tree

• Implementazione di IQueryable<T>

• La conversione a SQL avviene al momento di iterare il risultato della query (GetEnumerator)

var query = from c in Customers

where c.Country == "USA"

select c.CompanyName;

foreach( var company in query ) {

Console.WriteLine( company );

}

www.devleap.it

IEnumerator<string> enumerator = query.GetEnumerator();

while (enumerator.MoveNext()) {

Console.WriteLine( enumerator.Current ); }

C#

Manipolazione query

• Query LINQ to SQL possono essere composte tra loro – SQL generato solo per query eseguite

// All Customers

var query = from c in Customers

select new {c.CompanyName, c.State };

// Customers from Washington (WA)

query = from c in query

where c.State == “WA"

select c;

www.devleap.it