Eduardo Quintás - SABIA
Transcripción
Eduardo Quintás - SABIA
Eduardo Quintás Guía • • • • • • Novedades en C# 3.0 30 Fundamentos de LINQ Linq To Objects Linq To XML Li To Linq T Entities E titi Recursos Lenguaje Integrado de Consultas: LINQ Evolución de .NET 2002 2003 2005 2006 2007 2010 Herramienta (Visual Studio) VS 2002 VS 2003 VS2005 VS200 VS2005 VS2008 VS2010 Lenguaje C# v1.0 VB.NET (v7.0) C# v1.1 VB.NET (v7.1) C# v2.0 VB2005 (v8.0) como antes C# v3.0 VB9 (v9.0) C# 4.0 VB10 (v10.0) Librerías Lib í Framework NetFx v1.0 NetFx v1.1 NetFx v2.0 NetFx v3.0 NetFx v3.5 NetFx V4.0 Engine g e (CLR) CLR v1.0 CLR v1.1 CLR v2.0 como antes como antes CLR v4.0 + Extensiones C# 3.0 - Objetivos I Integrar objetos, bj d datos relacionales l i l 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 extensores, tipos anónimos anónimos, constructores sin parámetros, inferencia de tipos expresiones lambda, tipos, lambda árboles de expresión • Más un p poquito q de azucar sintáctico … from p in Passengers where p.Citizenship == “ES” select new { p.Id p p.Id, Id, p.Name p Name }; Nuevas características • • • • • • • Inicializadores de objetos Inferencia de tipos Ti Tipos anónimos ó i Métodos extensores Expresiones i lambda l bd Árboles de expresión LINQ!!! Inicializadores de Objetos public class Passenger { public string Id {get; set;} public string Name {get; set;} public DateTime BirthDate {get; set;} } public Passenger(string id, string name, DateTime birthDate) // OPCIONAL!!!! { Id=id; Name=name; BirthDate = birthDate; } Asignación A i ió de d Campos o Propiedades Passenger p = new Passenger () { Id = “A4”, Name = “Cabezabolo, Manolo” }; Passenger p = new Passenger(); p.Id = “A4”; A4 ; p.Name = “Cabezabolo, Manolo”; Inferencia f i de d Tipos i int 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 var var var var i = 666; s = “Hola"; d = 3.14; numbers = new int[] {1, 2, 3}; pedidos = new Dictionary<int,Pedido>(); p y , () “El tipo en el lado de la derecha” Tipos Anónimos class XXX { public string Name; public bli int i t Age; A } XXX var o = new { Name = “Pantoja”, Age= 75 }; Métodos Extensores Método extensor namespace MisCosas { public static class Extensiones { public static string Concatenar(this IEnumerable<string> strings strings, string separador) {…} } } using MisCosas; Incluir extensiones en el ámbito string[] nombres = new string[] { “Edu", “Juan", “Manolo" }; string s = nombres.Concatenar(", ( "); ) IntelliSense! obj.Foo(x, y) XXX.Foo(obj, x, y) Expresiones Lambda Delegado genérico public delegate bool Predicate<T>(T obj); public bli class l Li List<T> t<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; } … } Tipo Ti genérico Expresiones Lambda public class MiClase { public static void Main() { List<Cliente> clientes = ObtenerListaClientes(); List<Cliente> locales = clientes FindAll( clientes.FindAll( new Predicate<Cliente>(CiudadIgualCoruna) ); } static bool CiudadIgualCoruna(Cliente c) { return c.Ciudad == “A Coruña"; } } Expresiones Lambda p public class MiClase { public static void Main() { List<Cliente> clientes = ObtenerListaClientes (); List<Cliente> locales = clientes.FindAll( li t Fi dAll( delegate(Cliente c) { return c.Ciudad == “A Coruña"; } ); } } Delegado Anónimo ó i Expresiones Lambda public class MiClase { public static void Main() { List<Cliente> clientes = ObtenerListaClientes (); List<Cliente> locales = clientes.FindAll( (Clientes c) => {return c.Ciudad c Ciudad == “A Coruña";} ); } } Expresión Lambda Expresiones p Lambda public class MiClase { public static void Main() { List<Cliente> clientes = ObtenerListaClientes (); List<Cliente> locales = clientes.FindAll(c => c.Ciudad == “A Coruña"); } } Expresión Lambda Introduciendo LINQ • Todos estos nuevos aspectos se trasladan a métodos extensores sobre colecciones: ▫ Pueden transformarse en árboles de expresiones ffrom p in passengers i where p.Citizenship== “ES" select new { p Id p Name }; select new { p.Id, p.Name passengers .Where(p => c.Citizenship == “ES") .Select(p => new { p.Id, p.Name }); Introduciendo LINQ var pasajerosNacionales = from p in passengers where p.Citizenship == “ES" I f Inferencia i Tipos Variables select new {p.Id, p.Name}; Expresiones de C Consulta l Locales Expresiones Lambda var pasajerosNacionales = passengers .Where(p => p.Citizenship== “ES") .Select(p => new { p.Id, p.Name}); Select(p => new { p Id p Name}); Métodos Extensores Tipos p Anónimos Inicializadores de Objetos Lenguaje 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 e e c a de ttipos, pos, Tipos pos anónimos, a ó os, Métodos étodos eextensores te so es y Inicialización de objetos ▫ Altamente extensible • Múltiples Múlti l proveedores d Objects, XML, DataSets, SQL, Entities WMI, Sharepoint, Excel… incluso para Google, Flickr, Amazon L Language INt INtegrated t d Query Q (LINQ) VB Others Others… C# .NET Language-Integrated Query LINQ enabled data sources LINQ enabled ADO.NET LINQ To Objects LINQ T DataSets To D t S t LINQ T SQL To LINQ T Entities To E titi LINQ To XML <book> <title/> <author/> <price/> </book> Objects Relational XML Arquitectura de LINQ var query = from p in passengers where p.Citizenship== “ES" select p Fuente implementa IEnumerable<T> IEnumerable <T> Fuente implementa IQueryable<T> IQueryable <T> System.Linq.Enumerable Basado en delegados XML Objetos System.Linq.Queryable Basado en árbol de expresión SQL DataSets Entities Expresión ió de d Consulta C l Empieza p con from Cero o más from, join, let, where, o orderby from id in source { from id in source | join id in source on expr equals expr [ into [ into id ] | ]| let id = expr | Termina con where condition | select o group by orderby ordering, ordering, … } select expr | group expr by key [ into id query ] Continuación into opcional Expresiones de Consulta Proyección Select <expr> Filtrado Where <expr>, Distinct Comprobación Any(<expr>) All(<expr>) Any(<expr>), Union <expr> Join <expr> On <expr> Equals <expr> Agrupación Group By <expr>, <expr> <expr> Into <expr>, <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>, <expr> Take [ While ] <expr> Conjunto Union, Intersect, Except Ordenación Order By <expr>, <expr> <expr> [ Ascending | Descending ] Operadores de Consulta Expresión de consulta de Linq Where(), Select() Where() Select(), SelecMany(), SelecMany() OrderBy(), OrderBy() ThenBy(), ThenBy() OrderByDescending(), ThenByDescending(), GroupBy(), Join(), GroupJoin() Partición Take() Skip() Take(), Skip(), TakeWhile(), 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() Lenguaje 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 Lenguaje Integrado de Consultas: LINQ XML en .Net 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 l XmlDocument, l XmlNode l d … en System.Xmll ▫ Implementan un DOM por árboles • Ahora: LINQ To XML ▫ Extensión de LINQ de .Net ▫ Simple, Simple Flexible Flexible, Potente Potente, nuevo DOM 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 • Los métodos están sobrecargados para localizar elementos concretos. • Métodos más representativos .Load() Load() / .Save() Save() Cargan o Guardan de un stream un documento XML .Elements() Secuencia de elementos contenidos .ElementsBeforeSelf(), (), .ElementsAfterSelf() Elementos “hermanos” anteriores o p 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 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 (archivos, http 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") 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() … <TSAInformationForm Date="..."> <SourceID>...</SourceID> <PassengerList> <Passenger DocumentId="..."> <Name>..</Name> <Country> </Country> <Country>..</Country> <Flight Code="..."> <ArrivalDate>..</ArrivalDate> </Flight> </Passenger> ... </PassengerList> </TSAInformationForm> XElement nuevo = new XElement("TSAInformationForm", new XAttribute("Date", DateTime.Now), new XElement("SourceID", "883829HFGHMT"), new XElement( XElement("PassengerList", 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"); S ("T S dFil l") 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 Interface Lógica de negocio Almacén public class Facade ADO.NET ADO NET 3.0: 3 0: Entity Framework { Oracle public static IList<Blog> GetAllBlogUpdatedSince(UpdatedSince period) public partial class BlogContext : ObjectContext { { Modelo Lógico … DateTime dateBlog = FacadeHelper.getPeriod(period); public partial class :EntityObjects EntityObject EF Clases public p ObjectQuery<BlogPost> j y g BlogPosts g { Data UI / { using ctx = new BlogContext()) public(BlogContext static Blog CreateBlog(int blogID, Provider get string seriesTitle, bool needsReviewer) Fachada { UIC SqlServer SqlServer, { Stateless, IQueryable<Blog> blogs = from blog in ctx.Blogs { Webforms, Gestión Modelo== null)) Oracle, using BlogsSample.BusinessLogic.ADONET30; ((this._BlogPosts Short lived Blogif blog = where new Blog(); blog.BlogPosts.Any(p Console App, MySQL,=> p.BlogDate > date) ObjectContext, … { contexts blog.BlogID g g = blogID; g select blog; g; DB2, etc. ASP ASP.NET ObjectStateManager protected t tNET d void id B Button2_Click(object tt 2 Cli k( bj tblog.SeriesTitle sender, d this._BlogPosts E EventArgs tA = seriesTitle; e) ) = return blogs.ToList<Blog>(); { Web Services base.CreateQuery<BlogPost>("[BlogPosts]"); blog.NeedsReviewer = needsReviewer; } } blog; GridView2.DataSource = Facade.GetAllBlogUpdatedSince( CSDL return } <Schema Namespace="BlogsSample.BusinessLogic.ADONET30.Model" Alias="Self" return this._BlogPosts; }UpdatedSince.LastYear); } SGBD xmlns="http://schemas.microsoft.com/ado/2006/04/edm"> } Metadata GridView2.DataBind(); public int BlogID <EntityContainer Name="BlogContext"> } <E tit S t N Name="BlogPosts" "Bl P Archivos t " E EntityType="BlogsSample.BusinessLogic.ADONET30.Model.BlogPost" tit CSDL CSDL, T MSL "Bl y SSDL S l B i L i ADONET30 M d l Bl P t" / } { <EntitySet … … get { return this._BlogID; } public MSL voidset AddToBlogs(Blog blog) <?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"> base.AddObject("Blogs", blog); this.OnBlogIDChanging(value); Name="BlogPosts"> } <EntitySetMapping Visual del Modelo this <E titthis.ReportPropertyChanging( T Def. M ReportPropertyChanging("BlogID"); i T N "I T Of(Bl SBlogID l B ); i L i ADONET30 M d l Bl P t)"> <EntityTypeMapping TypeName="IsTypeOf(BlogsSample.BusinessLogic.ADONET30.Model.BlogPost)"> <MappingFragment StoreEntitySet="BlogPosts"> Archivo .EDMX | Edmgen.exe this._BlogID = StructuralObject.SetValidValue(value); <ScalarProperty Name="BlogPostID" ColumnName="BlogPostID" /> this.ReportPropertyChanged("BlogID"); … this.OnBlogIDChanged(); SSDL } <?xml version="1.0" encoding="utf-8"?> } } <Schema <S h N Namespace="BlogsSample.BusinessLogic.BlogsModel.Store" "Bl S l B i L i Bl M d l St " Ali Alias="Self" "S lf" 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" /> Modelo Conceptual en EF • Clases prescriptivas ▫ ▫ ▫ ▫ ▫ ▫ Structural Object j > EntityObject y j Gestión de identidad (EntityKey) Gestión de cambios (TrackingEntity g y 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 ac g de estado objetos: Tracking ▫ .Attach(..), .Dettach(..) ▫ ObjectStateManager ▫ MergeOption M O ti ObjectStateManager • Seguimiento del estado de entidades • Gest Gestiona o a eentradas t adas EntityStateEntry t tyState t y pa para a 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. Di ñ Entity Diseño: i Framework k EntityObject Bl Blog * 1 EntityStateEntry ObjectStateManager CurrentValues OriginalValues State IsRelationship Caché de Entidades Gestión de Identidad, estado y cambios en las Entidades Bl P t BlogPost BlogPostId: int BlogEntry: string … EntityKey EntityState: Added, Deleted, Detached,, Changed Unchanged Changed, PropertyChanged 1 ObjectContext BloggerCtx Blogs: ObjectQuery BlogPosts: ObjectQuery AddToBlogs(…) AddT Bl P t ( ) AddToBlogPosts(…) Hereda: Attach(..) Dettach(..) Add(..) ( ) Delete(..), Refresh(..) SaveChanges(..) etc. Consultas • Entity SQL ObjectQuery<Blog> query = ctx.CreateQuery<Blog>( "SELECT VALUE bp.Blogs p g FROM BlogPosts g as bp p WHERE bp.BlogDate p g > @date", new ObjectParameter("date",date)); ▫ Dialecto SQL Q indep. p de g gestor con soporte p p para: Tipos enriquecidos, relaciones, herencia… Strings que se resuelven en tiempo de ejecución • LINQ to Entities ii ▫ Todas las ventajas de LINQ (tipado fuerte, IQueryable<Blog> query = from posts in ctx.BlogPosts expresiones lambda) where posts.BlogDate > date ▫ Lenguaje que se resuelve en tiempo de select posts.Blogs; compilación ▫ Aprovechamos el tipado fuerte, la inferencia y el Intellisense de Visual Studio ▫ Menos errores en ejecución 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 bj o To XML Arquitectura de LINQ To Entities Operadores disponibles Expresió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 g ((FlightContext g ctx = new FlightContext()) g ()) { …}} ▫ Using • Dentro del contexto construír la consulta ▫ Obtener los IQueryable<T> del Contexto ▫ IQueryable<Flight> query = from f in ctx.Flights where h p.To==“MAD” T “MAD” select f; • Ejecutar la consulta ▫ Con un operador de conversión query ToList(); query.FirstOrDefault() query FirstOrDefault() … query.ToList(); Otras consideraciones • Pensar la consulta con el modelo conceptual ▫ Navegar por las relaciones y no con joins • Los objetos bj recuperados d dentro d d l contexto son del gestionados por el ObjectStateManager (tracking) • Cuando se cierra el contexto NO. 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( ctx Flights Include(“Aircraft”) Aircraft ) select f; ▫ Carga explícita if (!aflight.Aircraft.IsLoaded) aflight.Aircraft.Load(); fli ht Ai ft L d() Modelo ER Modelo EF Lenguaje Integrado de Consultas: LINQ Recursos • MSDN: http//Msdn.microsoft.com 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/ 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 ADO.NET NET Entity Framework” Framework , Unai Zorrilla, Zorrilla Octavio Hernández, Eduardo Quintás. Krasis Press 2008. ISBN: 978-84-935489-9-5