550 likes | 820 Views
Lenguaje Integrado de consultas LINQ. Eduardo 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.0. Lenguaje Integrado de Consultas: LINQ. Evolución de .NET. C# 3.0 - Objetivos.
E N D
Lenguaje Integrado de consultasLINQ Eduardo Quintás
Guía • Novedades en C# 3.0 • Fundamentos de LINQ • LinqToObjects • LinqTo XML • LinqToEntities • Recursos
Novedades en C#3.0 Lenguaje Integrado de Consultas: LINQ
C# 3.0 - Objetivos • Integrarobjetos, datosrelacionales y XML • Y: • Hacer el lenguajemásconciso • Añadirconstructores de programaciónfuncional • No ligar el lenguaje a APIs específicas • Mantenerse100% compatible haciaatrá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 … fromp inPassengers wherep.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 Objetos public class Passenger { public string Id {get; set;} public string Name {get; set;} public DateTimeBirthDate {get; set;} } Asignación de Campos o Propiedades public Passenger(string id, string name, DateTimebirthDate) // OPCIONAL!!!! { Id=id; Name=name; BirthDate = birthDate; } Passenger p = new Passenger () { Id = “A4”, Name = “Cabezabolo, Manolo” }; Passenger p = new Passenger(); p.Id= “A4”; p.Name= “Cabezabolo, Manolo”;
Inferencia de Tipos inti = 666; string s = “Hola"; double d = 3.14; int[] numbers = new int[] {1, 2, 3}; Dictionary<int,Pedido> pedidos= new Dictionary<int,Pedido>(); vari = 666; var s = “Hola"; var d = 3.14; var numbers = new int[] {1, 2, 3}; varpedidos= new Dictionary<int,Pedido>(); “El tipo en el lado de la derecha”
TiposAnónimos class XXX { public string Name; public intAge; } XXX var o = new { Name = “Pantoja”, Age= 75 };
Método extensor MétodosExtensores namespace MisCosas { public static class Extensiones { public static string Concatenar(this IEnumerable<string> strings, string separador) {…} } } Incluirextensiones en el ámbito using MisCosas; string[] nombres= new string[] { “Edu", “Juan", “Manolo" }; string s = nombres.Concatenar(", "); obj.Foo(x, y) XXX.Foo(obj, x, y) IntelliSense!
Expresiones Lambda Delegadogenérico 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; } … } Tipo genérico
Expresiones Lambda public class MiClase { public static void Main() { List<Cliente> clientes= ObtenerListaClientes(); List<Cliente> locales = clientes.FindAll( new Predicate<Cliente>(CiudadIgualCoruna) ); } static boolCiudadIgualCoruna(Clientec) { 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(Clientec) { return c.Ciudad == “A Coruña"; } ); } } Delegado Anónimo
Expresiones Lambda public class MiClase { public static void Main() { List<Cliente> clientes= ObtenerListaClientes (); List<Cliente> locales = clientes.FindAll( (Clientesc) => {return c.Ciudad== “A Coruña";} ); } } Expresión Lambda
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ón Lambda
Introduciendo LINQ • Todosestosnuevosaspectos se trasladan a métodosextensoressobrecolecciones: • Puedentransformarse en árboles de expresiones from p in passengers where p.Citizenship== “ES" select new { p.Id, p.Name}; passengers .Where(p => c.Citizenship== “ES") .Select(p => new { p.Id, p.Name});
Introduciendo LINQ Expresiones de Consulta varpasajerosNacionales= from p in passengers where p.Citizenship== “ES" select new {p.Id, p.Name}; InferenciaTipos Variables Locales Expresiones Lambda varpasajerosNacionales = passengers .Where(p => p.Citizenship== “ES") .Select(p => new { p.Id, p.Name}); MétodosExtensores TiposAnónimos Inicializadores de Objetos
Fundamentos de LINQ Lenguaje Integrado de Consultas: LINQ
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 LINQ: LenguageIntegratedQuery
LINQ enabled data sources Others… Language INtegrated Query (LINQ) C# VB .NET Language-Integrated Query LINQ enabled ADO.NET LINQ To XML LINQ To DataSets LINQ To Entities LINQ To Objects LINQ To SQL <book> <title/> <author/> <price/> </book> Relational Objects XML
Arquitectura de LINQ var query = from p in passengers where p.Citizenship== “ES" select p Fuente implementaIEnumerable<T> Fuente implementaIQueryable<T> System.Linq.EnumerableBasado en delegados System.Linq.QueryableBasado en árbol de expresión Objetos SQL DataSets Entities XML
Expresión de Consulta Empieza con from Cero o másfrom, join, let, where, o orderby fromidinsource { fromidinsource | joinidinsourceonexprequalsexpr [ intoid ] | letid = expr | wherecondition | orderbyordering, ordering, … } selectexpr | groupexprbykey [ intoidquery ] Termina con selecto group by Continuaciónintoopcional
LINQ toObjects Lenguaje Integrado de Consultas: LINQ
Aplicable en colecciones genéricas y arrays que están en memoria (heap) • Métodos extensores para colecicones y arrays • UsingSystem.Linq; • Las expresiones de consulta devuelven IEnumerable<T> • Fundamental para gestionarlas de modo flexible LINQ ToObjects
LINQ to XML Lenguaje Integrado de Consultas: LINQ
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 XML en .Net Framework
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 LINQ To XML
Los métodos están sobrecargados para localizar elementos concretos. Métodos más representativos Clase XElement
Directamente con XElement Creación de documentos 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");
Load(uri) (archivos, http…) Métodos Elements, Attributes, Element, Attribute … Se puede utilizar Xpath (método XPathSelectElements()) Consultas XElement element = XElement.Load(Server.MapPath(@"~\XmlFiles\rssMiniNova.xml")); … XElementelement = 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 };
Utilizando Linq y XElement Método Save(stream/fichero… ), ToString() … Transformación de documentos <TSAInformationForm Date="..."> <SourceID>...</SourceID> <PassengerList> <Passenger DocumentId="..."> <Name>..</Name> <Country>..</Country> <Flight Code="..."> <ArrivalDate>..</ArrivalDate> </Flight> </Passenger> ... </PassengerList> </TSAInformationForm> XElementnuevo = 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");
Arquitectura Entitiy Framework (EF) LINQ toEntities Ejemplos LINQ toEntities
Arquitectura de EF • OR/M + Objetos de Servicio • Soportede variosSGDB: EntityClientProvider • Herramientas y lenguajeparamapeado • Modelo Conceptual: EntityObject • Contextostipados: 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 ADO.NET 3.0: Entity Framework Oracle UI / UIC Webforms, ConsoleApp, ASP.NET Web Services Fachada Stateless, Short livedcontexts publicclassFacade { public static IList<Blog> GetAllBlogUpdatedSince(UpdatedSince period) { DateTime date = FacadeHelper.getPeriod(period); using (BlogContextctx = new BlogContext()) { IQueryable<Blog> blogs = from blog in ctx.Blogs whereblog.BlogPosts.Any(p => p.BlogDate > date) select blog; returnblogs.ToList<Blog>(); } } } Modelo Lógico Clases EntityObjects EF DataProvider SqlServer, Oracle, MySQL, DB2, etc. 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(); } } ... } SqlServer Gestión Modelo ObjectContext, ObjectStateManager using BlogsSample.BusinessLogic.ADONET30; … protected void Button2_Click(object sender, EventArgs e) { GridView2.DataSource = Facade.GetAllBlogUpdatedSince( UpdatedSince.LastYear); GridView2.DataBind(); } 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" /> Metadata Archivos CSDL, MSL y SSDL Def. Visual del Modelo Archivo .EDMX | Edmgen.exe ADO.NET 3.0
Clases prescriptivas • StructuralObject > EntityObject • Gestión de identidad (EntityKey) • Gestión de cambios (TrackingEntityevent) • Soporte para relaciones (EntityCollection) • Estado (EntityState) • Son clases parciales • Posibilidad de clases IPOCO • Implementar IEntityWithKey, IEntityWithChangeTracker, IEntityWithRelationship Modelo Conceptual en EF
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 ObjectContext
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. ObjectStateManager
Diseño: Entity Framework 1 EntityObject 1 EntityStateEntry ObjectStateManager ObjectContext CurrentValues OriginalValues State IsRelationship Caché de Entidades Gestión de Identidad, estado y cambios en las Entidades BloggerCtx Blog * BlogPost Blogs:ObjectQuery BlogPosts:ObjectQuery AddToBlogs(…) AddToBlogPosts(…) Hereda: Attach(..) Dettach(..) Add(..) Delete(..), Refresh(..) SaveChanges(..) etc. BlogPostId: int BlogEntry: string … EntityKey EntityState: Added, Deleted, Detached, Changed, Unchanged PropertyChanged
Entity SQL • Dialecto SQL indep. de gestor con soporte para: • Tipos enriquecidos, relaciones, herencia… • Strings que se resuelven en tiempo de ejecución • LINQ toEntities • 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 Consultas ObjectQuery<Blog> query = ctx.CreateQuery<Blog>( "SELECT VALUE bp.Blogs FROM BlogPosts as bp WHERE bp.BlogDate > @date", new ObjectParameter("date",date)); IQueryable<Blog> query = from posts inctx.BlogPosts whereposts.BlogDate > date selectposts.Blogs;
LINQ To Entities • Diferencias con LINQ To Objects y To XML • Las consultastienen el tipoObjectQuery<T> • ImplementaIQueryable<T> y no IEnumerable<T> • NecesitaÁrboles de expresiónparaconstruir el SQL final. • Cuando se enumeran los resultados: • query1.FirstOrDefault(), query1.ToList() … • Se ejecuta la consulta SQL y devuelve un IEnumerable<T> • No estándisponiblestodos los operadores de Linq To Objects o To XML
Cómohacerunaconsulta • Establecer el contexto • Using (FlightContextctx = new FlightContext()) { …} • Dentro del contextoconstruí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() …
Otrasconsideraciones • Pensar la consulta con el modelo conceptual • Navegarporlasrelaciones y no con joins • Los objetosrecuperadosdentro del contexto son gestionadospor el ObjectStateManager (tracking) • Cuando se cierra el contextoNO. • CargaPerezosa de relaciones (dentro de un contexto) • ¡¡No nos lo vamos a traertodo!! • Si en el where se utilizaunarelación, ésta se carga • Cargaimplícita • from f in ctx.Flights.Include(“Aircraft”) select f; • Cargaexplícita • if (!aflight.Aircraft.IsLoaded)aflight.Aircraft.Load();