Eduardo Quintás. Guía Novedades en C# 3.0 Fundamentos de LINQ Linq To Objects Linq To XML Linq To...

Post on 02-Feb-2016

240 views 0 download

Transcript of Eduardo Quintás. Guía Novedades en C# 3.0 Fundamentos de LINQ Linq To Objects Linq To XML Linq To...

Lenguaje Integrado de consultasLINQEduardo Quintás

Guía

•Novedades en C# 3.0•Fundamentos de LINQ•Linq To Objects•Linq To XML•Linq To Entities•Recursos

Novedades en C#3.0Lenguaje Integrado de Consultas: LINQ

Evolución de .NET2002 2003 2005 2006 2007 2010

Herramienta(Visual Studio)

VS 2002 VS 2003 VS2005VS2005

+ Extensiones

VS2008 VS2010

LenguajeC# v1.0VB.NET (v7.0)

C# v1.1VB.NET (v7.1)

C# v2.0VB2005 (v8.0)

como antes

C# v3.0VB9

(v9.0)

C# 4.0VB10

(v10.0)

Librerías Framework

NetFx v1.0

NetFx v1.1

NetFx v2.0

NetFx v3.0

NetFx v3.5

NetFxV4.0

Engine (CLR) CLR v1.0 CLR v1.1 CLR v2.0 como

antescomo antes

CLR v4.0

C# 3.0 - Objetivos

Integrar objetos, datos relacionales y XML

Y:

Hacer el lenguaje más conciso

Añadir constructores de programación

funcional

No ligar el lenguaje a APIs específicas

Mantenerse 100% compatible hacia atrás

Resultado:

•Métodos extensores, tipos anónimos, constructores sin parámetros, inferencia de tipos, expresiones lambda, árboles de expresión

•Más un poquito de azucar sintáctico …

from p in Passengerswhere p.Citizenship == “ES”select new { p.Id, p.Name };

Nuevas características

•Inicializadores de objetos•Inferencia de tipos•Tipos anónimos•Métodos extensores•Expresiones lambda•Árboles de expresión•LINQ!!!

Inicializadores de Objetospublic class Passenger{ public string Id {get; set;} public string Name {get; set;} public DateTime BirthDate {get; set;}}

Passenger p = new Passenger () { Id = “A4”, Name = “Cabezabolo, Manolo” };

Passenger p = new Passenger();p.Id = “A4”;p.Name = “Cabezabolo, Manolo”;

Asignación de Campos o

Propiedadespublic Passenger(string id, string name, DateTime birthDate) // OPCIONAL!!!!{ Id=id; Name=name; BirthDate = birthDate; }

Inferencia de Tiposint i = 666;string s = “Hola";double d = 3.14;int[] numbers = new int[] {1, 2, 3};Dictionary<int,Pedido> pedidos = new Dictionary<int,Pedido>();

var i = 666;var s = “Hola";var d = 3.14;var numbers = new int[] {1, 2, 3};var pedidos = new Dictionary<int,Pedido>();

“El tipo en el lado de la derecha”

Tipos Anónimos

var o = new { Name = “Pantoja”, Age= 75 };

class XXX{ public string Name; public int Age;}

XXX

Métodos Extensoresnamespace MisCosas{ public static class Extensiones { public static string Concatenar(this IEnumerable<string> strings, string separador) {…} }}

using MisCosas;

string[] nombres = new string[] { “Edu", “Juan", “Manolo" };string s = nombres.Concatenar(", ");

Método extensor

Incluir extensiones en el ámbito

obj.Foo(x, y)

XXX.Foo(obj, x, y)

IntelliSense!

Expresiones Lambda

public delegate bool Predicate<T>(T obj);

public class List<T>{ public List<T> FindAll(Predicate<T> test) { List<T> result = new List<T>(); foreach (T item in this) if (test(item)) result.Add(item); return result; } …}

Delegado genérico

Tipogenérico

Expresiones Lambda

public class MiClase{ public static void Main() { List<Cliente> clientes = ObtenerListaClientes(); List<Cliente> locales = clientes.FindAll( new Predicate<Cliente>(CiudadIgualCoruna) ); }

static bool CiudadIgualCoruna(Cliente c) { return c.Ciudad == “A Coruña"; }}

Expresiones Lambda

public class MiClase{ public static void Main() { List<Cliente> clientes = ObtenerListaClientes (); List<Cliente> locales = clientes.FindAll( delegate(Cliente c) { return c.Ciudad == “A Coruña"; } ); }}

DelegadoAnónimo

Expresiones Lambda

public class MiClase{ public static void Main() { List<Cliente> clientes = ObtenerListaClientes (); List<Cliente> locales = clientes.FindAll( (Clientes c) => {return c.Ciudad == “A Coruña";} ); }}

ExpresiónLambda

Expresiones Lambda

public class MiClase{ public static void Main() { List<Cliente> clientes = ObtenerListaClientes (); List<Cliente> locales = clientes.FindAll(c => c.Ciudad == “A Coruña"); }}

ExpresiónLambda

Introduciendo LINQ

•Todos estos nuevos aspectos se trasladan a métodos extensores sobre colecciones:▫Pueden transformarse en árboles de

expresiones

from p in passengerswhere p.Citizenship== “ES"select new { p.Id, p.Name };

passengers.Where(p => c.Citizenship == “ES").Select(p => new { p.Id, p.Name });

var pasajerosNacionales = from p in passengers where p.Citizenship == “ES" select new {p.Id, p.Name};

var pasajerosNacionales = passengers .Where(p => p.Citizenship== “ES") .Select(p => new { p.Id, p.Name});

Métodos Extensore

s

Expresiones

Lambda

Expresiones de Consulta

Inicializadores de Objetos

Tipos Anónimos

Inferencia Tipos

Variables Locales

Introduciendo LINQ

Fundamentos de LINQLenguaje Integrado de Consultas: LINQ

LINQ: Lenguage Integrated Query

• Lenguaje de consulta universal de primer orden en C# y VB9▫ Reducir el conocimiento de distintas formas de consulta.▫ Parecido a lo que ya conocemos : SQL▫ Basado en Lambda Cálculo, Tipado fuerte, Ejecución

retrasada (deferred) Utiliza características nuevas del lenguaje como: Inferencia de tipos, Tipos anónimos, Métodos extensores y Inicialización de objetos

▫ Altamente extensible

• Múltiples proveedores Objects, XML, DataSets, SQL, Entities WMI, Sharepoint, Excel… incluso para Google, Flickr,

Amazon

Language INtegrated Query (LINQ)

LINQ enabled data sources

LINQTo Objects

Objects

LINQTo XML

<book> <title/> <author/> <price/></book>

XML

LINQ enabled ADO.NET

LINQTo DataSets

LINQTo SQL

LINQTo Entities

Relational

Others…VB C#

.NET Language-Integrated Query

Arquitectura de LINQ

System.Linq.EnumerableBasado en delegados

Fuente implementaIEnumerable<T>

var query = from p in passengers where p.Citizenship== “ES" select p

System.Linq.QueryableBasado en árbol de

expresión

Fuente implementaIQueryable<T>

SQL DataSetsObjetos EntitiesXML

Expresión de Consulta

from id in source{ from id in source | join id in source on expr equals expr [ into id ] | let id = expr | where condition | orderby ordering, ordering, … } select expr | group expr by key[ into id query ]

Empieza con from

Cero o más from, join, let, where, o orderby

Termina conselect o group

by

Continuación into opcional

Expresiones de ConsultaProyección Select <expr>

Filtrado Where <expr>, Distinct

Comprobación

Any(<expr>), All(<expr>)

Union <expr> Join <expr> On <expr> Equals <expr>

Agrupación Group By <expr>, <expr> Into <expr>, <expr>Group Join <decl> On <expr> Equals <expr> Into <expr>

Agregación Count(<expr>), Sum(<expr>), Min(<expr>), Max(<expr>), Avg(<expr>)

Partición Skip [ While ] <expr>, Take [ While ] <expr>

Conjunto Union, Intersect, Except

Ordenación Order By <expr>, <expr> [ Ascending | Descending ]

Operadores de ConsultaExpresión de consulta de Linq

Where(), Select(), SelecMany(), OrderBy(), ThenBy(), OrderByDescending(), ThenByDescending(), GroupBy(), Join(), GroupJoin()

Partición Take(), Skip(), TakeWhile(), SkipWhile()

Conjunto Distinct(), Union(), Intersect(), Except()

Conversión ToArray(), ToList(), ToDictionary(), ToLookup(), AsEnumerable(), Cast<T>(), OfType<T>()

Generación Range(), Repeat<T>(), Empty<T>(), Concat(), Reverse()

Cuantificación Any(), All(), Contains(), SequenceEqual()

Elementos First(), Last(), Single(), ElementAt(), DefaultIfEmpty(). {método}OrDefault()

Agregados Count(), LongCount(), Max(), Min(), Sum(), Average(), Aggregate()

LINQ to ObjectsLenguaje Integrado de Consultas: LINQ

LINQ To Objects• Aplicable en colecciones genéricas y arrays que

están en memoria (heap)• Métodos extensores para colecicones y arrays

▫ Using System.Linq;• Las expresiones de consulta devuelven

IEnumerable<T>• Fundamental para gestionarlas de modo flexible

Ejemplos de consultas

LINQ to XMLLenguaje Integrado de Consultas: LINQ

XML en .Net Framework• Clases XmlTextReader y XmlTextWriter

▫ L/E secuencial: Eficiente pero complejo• Serialización y Deserialización:

System.Xml.Serialization▫ Atributos en clases, S/D contra streams (ficheros,

memoria…)• Clases XmlDocument, XmlNode … en System.Xml

▫ Implementan un DOM por árboles• Ahora: LINQ To XML

▫ Extensión de LINQ de .Net▫ Simple, Flexible, Potente, nuevo DOM.▫ Manipulación y consulta con LINQ

LINQ To XML• Importando System.Xml.Linq• Nuevo DOM:

▫ Construcción funcional: XElement• Independencia del documento

▫ Permite crear fragmentos XML sin asociarlos a un XDocument

• Texto como valor▫ Hojas del árbol XML se convierten a tipos por valor

de .Net

Clase XElement

.Load() / .Save() Cargan o Guardan de un stream un documento XML

.Elements() Secuencia de elementos contenidos

.ElementsBeforeSelf(), .ElementsAfterSelf()

Elementos “hermanos” anteriores o posteriores en el mismo nivel del árbol

.Descendants{AndSelf}()

Secuencia aplanada de todos los elementos hijos

.Ancestors{AndSelf}()

Secuencia aplanada de todos los elementos padres

.Attributes() Atributos del elemento

• Los métodos están sobrecargados para localizar elementos concretos.

• Métodos más representativos

Creación de documentos• Directamente con XElement

XElement contacts = new XElement("Contacts", new XElement("Contact", new XElement("Name", "Patrick Hines"), new XElement("Phone", "206-555-0144", new XAttribute("Type", "Home")), new XElement("phone", "425-555-0145", new XAttribute("Type", "Work")), new XElement("Address", new XElement("Street1", "123 Main St"), new XElement("City", "Mercer Island"), new XElement("State", "WA"), new XElement("Postal", "68042"))));contacts.Save("contacts.xml");

Consultas• Load(uri) (archivos, http…)• Métodos Elements, Attributes, Element, Attribute …• Se puede utilizar Xpath (método

XPathSelectElements())

XElement element = XElement.Load(Server.MapPath(@"~\XmlFiles\rssMiniNova.xml"));…XElement element = XElement.Load(@"http://www.mininova.org/rss.xml?cat=8");

var query = from i in element.Elements("channel").Elements("item") select new { Title = i.Element("title").Value, Posted = DateTime.Parse(i.Element("pubDate").Value), Size = Convert.ToDecimal(i.Element("enclosure").

Attribute("length").Value) Link = i.Element("enclosure").Attribute("url").Value, Category = i.Element("category").Value };

Transformación de documentos• Utilizando Linq y XElement• Método Save(stream/fichero… ), ToString() …

XElement nuevo = new XElement("TSAInformationForm", new XAttribute("Date", DateTime.Now), new XElement("SourceID", "883829HFGHMT"), new XElement("PassengerList", from p in pasajeros select new XElement("Passenger", new XAttribute("DocumentId", p.Id), new XElement("Name", p.Name), new XElement("Country", p.Citizenship), new XElement("Flight", new XAttribute("Code",p.Code), new XElement("ArrivalDate",p.Arrival)

))));

nuevo.Save("TsaSendFile.xml");

<TSAInformationForm Date="..."> <SourceID>...</SourceID> <PassengerList> <Passenger DocumentId="..."> <Name>..</Name> <Country>..</Country> <Flight Code="..."> <ArrivalDate>..</ArrivalDate> </Flight> </Passenger> ... </PassengerList> </TSAInformationForm>

LINQ to Entities• Arquitectura Entitiy Framework (EF)• LINQ to Entities • Ejemplos

Arquitectura de EF

•OR/M + Objetos de Servicio▫Soporte de varios SGDB:

EntityClientProvider▫Herramientas y lenguaje para mapeado▫Modelo Conceptual: EntityObject▫Contextos tipados: ObjectContext▫Gestión de Entidades:

ObjectStateManager▫Consulta: eSQL y LINQ To Entities

Patrón arquitectónico empresarial típico

UI / UICWebforms,

Console App,

ASP.NETWeb

Services

ADO.NET 3.0: Entity Framework

FachadaStateless,Short lived contexts

Modelo LógicoClases EntityObjects

Gestión Modelo

ObjectContext, ObjectStateManager

Oracle

SqlServer

Interface Lógica de negocio Almacén

ADO.NET 3.0

Def. Visual del Modelo

Archivo .EDMX | Edmgen.exe

EFDataProviderSqlServer, Oracle, MySQL, DB2, etc.

MetadataArchivos CSDL, MSL y SSDL

SGBD

CSDL<Schema Namespace="BlogsSample.BusinessLogic.ADONET30.Model" Alias="Self" xmlns="http://schemas.microsoft.com/ado/2006/04/edm"> <EntityContainer Name="BlogContext"> <EntitySet Name="BlogPosts" EntityType="BlogsSample.BusinessLogic.ADONET30.Model.BlogPost" /…MSL<?xml version="1.0" encoding="utf-8"?><Mapping Space="C-S" xmlns="urn:schemas-microsoft-com:windows:storage:mapping:CS"> <EntityContainerMapping StorageEntityContainer="dbo" CdmEntityContainer="BlogContext"> <EntitySetMapping Name="BlogPosts"> <EntityTypeMapping TypeName="IsTypeOf(BlogsSample.BusinessLogic.ADONET30.Model.BlogPost)"> <MappingFragment StoreEntitySet="BlogPosts"> <ScalarProperty Name="BlogPostID" ColumnName="BlogPostID" />…

SSDL<?xml version="1.0" encoding="utf-8"?><Schema Namespace="BlogsSample.BusinessLogic.BlogsModel.Store" Alias="Self" ProviderManifestToken="09.00.3042" xmlns="http://schemas.microsoft.com/ado/2006/04/edm/ssdl"> <EntityContainer Name="dbo"> <EntitySet Name="BlogComments" EntityType="BlogsSample.BusinessLogic.BlogsModel.Store.BlogComments" />

public partial class BlogContext : ObjectContext {… public ObjectQuery<BlogPost> BlogPosts { get { if ((this._BlogPosts == null)) { this._BlogPosts =

base.CreateQuery<BlogPost>("[BlogPosts]"); } return this._BlogPosts; } }… public void AddToBlogs(Blog blog) { base.AddObject("Blogs", blog); }

public partial class Blog : EntityObject { public static Blog CreateBlog(int blogID, string seriesTitle, bool needsReviewer) { Blog blog = new Blog(); blog.BlogID = blogID; blog.SeriesTitle = seriesTitle; blog.NeedsReviewer = needsReviewer; return blog; } public int BlogID { get { return this._BlogID; } set { this.OnBlogIDChanging(value); this.ReportPropertyChanging("BlogID"); this._BlogID = StructuralObject.SetValidValue(value); this.ReportPropertyChanged("BlogID"); this.OnBlogIDChanged(); } }

... }

public class Facade{ public static IList<Blog> GetAllBlogUpdatedSince(UpdatedSince period) { DateTime date = FacadeHelper.getPeriod(period);

using (BlogContext ctx = new BlogContext()) { IQueryable<Blog> blogs = from blog in ctx.Blogs where blog.BlogPosts.Any(p => p.BlogDate > date) select blog; return blogs.ToList<Blog>(); } }}

using BlogsSample.BusinessLogic.ADONET30;…protected void Button2_Click(object sender, EventArgs e){ GridView2.DataSource = Facade.GetAllBlogUpdatedSince( UpdatedSince.LastYear); GridView2.DataBind();}

Modelo Conceptual en EF

• Clases prescriptivas▫Structural Object > EntityObject ▫Gestión de identidad (EntityKey)▫Gestión de cambios (TrackingEntity event)▫Soporte para relaciones (EntityCollection)▫Estado (EntityState)▫Son clases parciales

• Posibilidad de clases IPOCO▫Implementar IEntityWithKey,

IEntityWithChangeTracker, IEntityWithRelationship

Object Context• Clase derivada (generada) de ObjectContext• Tipado Fuerte: Manipulación del Modelo Conceptual

▫ Consultas/Recuperación: Blogs: ObjectQuery;▫ Inserciones: .AddToBlog(Blog b); .AddObject(…), ▫ Borrado: .DeleteObject▫ Persistencia: .SaveChanges();

• Gestión de la conexión• Metadata (a partir de CSDL)• Almacen o caché en memoria de objetos• Tracking de estado objetos:

▫ .Attach(..), .Dettach(..) ▫ ObjectStateManager▫ MergeOption

ObjectStateManager•Seguimiento del estado de entidades•Gestiona entradas EntityStateEntry para

cada Entidad en almacen en memoria.▫Cuando se cargan (Query, Attach): Unchanged▫Cuando se crean (AddObject): Added▫Cuando se modifican: Changed▫Cuando se borran: Deleted▫Cuando se destruye el ObjectContext:

Detached▫Al aplicar ObjectContext.SaveChanges() en

Added, Changed, cambia a Unchanged.

Diseño: Entity FrameworkEntityObject ObjectContext

BloggerCtx

Blogs: ObjectQueryBlogPosts: ObjectQueryAddToBlogs(…)AddToBlogPosts(…)Hereda:Attach(..)Dettach(..)Add(..)Delete(..),Refresh(..)SaveChanges(..) etc.

ObjectStateManager1

Caché de EntidadesGestión de Identidad, estado ycambios en las Entidades

1 EntityStateEntry

CurrentValuesOriginalValuesStateIsRelationship

Blog BlogPost*

BlogPostId: intBlogEntry: string…

EntityKey EntityState:Added, Deleted, Detached, Changed, UnchangedPropertyChanged

Consultas•Entity SQL

▫Dialecto SQL indep. de gestor con soporte para: Tipos enriquecidos, relaciones, herencia… Strings que se resuelven en tiempo de ejecución

•LINQ to Entities▫Todas las ventajas de LINQ (tipado fuerte,

expresiones lambda)▫Lenguaje que se resuelve en tiempo de

compilación▫Aprovechamos el tipado fuerte, la inferencia y

el Intellisense de Visual Studio▫Menos errores en ejecución

IQueryable<Blog> query = from posts in ctx.BlogPosts where posts.BlogDate > date select posts.Blogs;

ObjectQuery<Blog> query = ctx.CreateQuery<Blog>( "SELECT VALUE bp.Blogs FROM BlogPosts as bp WHERE bp.BlogDate > @date", new ObjectParameter("date",date));

LINQ To Entities• Diferencias con LINQ To Objects y To XML• Las consultas tienen el tipo ObjectQuery<T>

▫ Implementa IQueryable<T> y no IEnumerable<T>▫Necesita Árboles de expresión para construir el

SQL final.• Cuando se enumeran los resultados:

▫query1.FirstOrDefault(), query1.ToList() …▫Se ejecuta la consulta SQL y devuelve un

IEnumerable<T>• No están disponibles todos los operadores de

Linq To Objects o To XML

Arquitectura de LINQ To Entities

Operadores disponiblesExpresión de consulta de Linq

Where(), Select(), SelecMany(), OrderBy(), ThenBy(), OrderByDescending(), ThenByDescending(), GroupBy(), Join(), GroupJoin()

Partición Take(), Skip()

Conjunto Distinct(), Union(), Intersect(), Except()

Conversión ToArray(), ToList(), ToDictionary(), ToLookup(), AsEnumerable(), Cast<T>(), OfType<T>()

Generación N/A

Cuantificación Any(), All()

Elementos First(), Last(), ElementAt(). {método}OrDefault()

Agregados Count(), LongCount(), Max(), Min(), Sum(), Average()

Cómo hacer una consulta• Establecer el contexto

▫Using (FlightContext ctx = new FlightContext()) { …}

• Dentro del contexto construír la consulta▫Obtener los IQueryable<T> del Contexto▫IQueryable<Flight> query =

from f in ctx.Flightswhere p.To==“MAD”select f;

• Ejecutar la consulta▫Con un operador de conversión

query.ToList(); query.FirstOrDefault() …

Otras consideraciones• Pensar la consulta con el modelo conceptual

▫ Navegar por las relaciones y no con joins• Los objetos recuperados dentro del contexto son

gestionados por el ObjectStateManager (tracking)• Cuando se cierra el contexto NO.• Carga Perezosa de relaciones (dentro de un

contexto)▫ ¡¡No nos lo vamos a traer todo!!▫ Si en el where se utiliza una relación, ésta se carga▫ Carga implícita

from f in ctx.Flights.Include(“Aircraft”) select f;▫ Carga explícita

if (!aflight.Aircraft.IsLoaded) aflight.Aircraft.Load();

Modelo ER

Modelo EF

RecursosLenguaje Integrado de Consultas: LINQ

Recursos• MSDN: http//Msdn.microsoft.com• 101 Linq Samples:

http://msdn.microsoft.com/en-us/vcsharp/aa336746.aspx • Blogs:

▫ ADO.NET Team Blog: http://blogs.msdn.com/adonet/ ▫ Blog de Dany Simons: http://blogs.msdn.com/dsimmons/ ▫ Blog de Unai Zorrilla: http://geeks.ms/blogs/unai/ ▫ Blog de Octavio Hdez.: http://geeks.ms/blogs/ohernandez/

• Libros:▫ “C# 3.0 y LINQ”, Octavio Hernández. Krasis Press 2007.

ISBN: 978-84-935489-1-9▫ “ADO.NET Entity Framework”, Unai Zorrilla, Octavio

Hernández, Eduardo Quintás. Krasis Press 2008. ISBN: 978-84-935489-9-5