230 likes | 490 Views
LINQ ( Language-Integrated Query ). Gabriel Espinoza Erices 2012 – 03 – 15. INTRODUCCIÓN. LINQ es una innovación para disminuir la brecha entre el mundo de los objetos y el mundo de los datos. INTRODUCCIÓN . En Visual Studio, se pueden escribir consultas LINQ en VB o C# con:
E N D
LINQ(Language-IntegratedQuery) Gabriel Espinoza Erices 2012 – 03 – 15
INTRODUCCIÓN • LINQ es una innovación para disminuir la brecha entre el mundo de los objetos y el mundo de los datos.
INTRODUCCIÓN • En Visual Studio, se pueden escribir consultas LINQ en VB o C# con: • Bases de datos SQL Server (Linqto SQL) • Documentos XML (Linqto XML) • DataSets ADO.NET (LinqtoDataSet) • Colecciones de objetos que soporten IEnumerable o IEnumerable<T> • Requiere .NET Framework 3.5+
QUERYABLE TYPES • Los tipos que soportan IEnumerable<T> o derivan de interfaces como IQueryable<T> son llamados QueryableTypes • Un objeto “queryabletype” no requiere modificación ni trato especial para servir como datasource de LINQ. • Si los datos orígenes no están en memoria como “queryabletype”, el proveedor de LINQ debe representarlo como si estuviera.
LINQ TO SQL COMO QUERYABLE TYPE Con LINQ to SQL, primero se crea un mapeo objeto-relacional en tiempo de diseño, se crean las querys contra esos objetos. Luego en tiempo de ejecución, LINQ to SQL maneja la comunicación con la base de datos.
LA QUERY • La query especifica qué información obtener de una o varias fuentes. Opcionalmente la query también puede especificar como esos datos deben ser ordenados, agrupados y formados antes de ser retornada. • Una query tiene 3 clausulas: • from: Especifica el data source • where: aplica el filtro • select: especifica el tipo de los elementos retornados.
EJECUCIÓN DE LA QUERY La query por si misma no ejecuta ninguna acción ni retorna datos. Solo almacena la información requerida para producir los resultados cuando la consulta sea ejecutada en un punto posterior.
FORZAR EJECUCIÓN INMEDIATA • Las querys que realizan funciones de agregado sobre un rango de fuentes, primero deben iterar sobre esos elementos. Ej: Count, Max, Average, First, etc. Notar que estas consultas no retornan una colección, sino que un valor. • Para forzar la ejecución inmediata de cualquier query y almacenar en cache sus resultados, se pueden usar el ToList<T> o ToArray<T>
SINTAXIS Son equivalentes
OPERACIONES BÁSICAS Range Variable Delcaración del DataSource DataSource Declaración de filtros Da “forma” al resultado de la query
ORDER BY & JOINS Ordenamiento Un join crea asociaciones entre secuencias que no estén explicitamente modeladas en los DataSources. En LINQ los join SIEMPRE funcionan contra objetos y no tablas de bases de datos
AGRUPAR Agrupar: Al agrupar, se forma una lista de listas. La cláusula group permite agrupar los resultados basados en una llave que se especifique. Ejemplo: Los resultados agrupados por ciudad, de tal manera que los clientes de Londres o Paris son grupos individuales. En este caso cust.City es la llave. Si se necesita interactuar con el grupo, se puede usar into para crear una variable que lo referencie
LINQ y CLASES GENÉRICAS • IEnumerable<T> es la interfaz que habilita que las colecciones de clases genéricas puedan ser enumeradas usando la sentencia foreach. Las colecciones de clases genéricas soportan IEnumerable<T> tal como las colecciones no genéricas (arraylists). • Cuando veas que una query está escripta como IEnumerable<Customer>, significa que la query, cuando sea ejecutada, producirá una secuencia de 0 o más objetos Customer.
LINQ y CLASES GENÉRICAS Se puede dejar que el compilador maneje la declaración genérica.
POR QUÉ LINQ VENCE A SQL SELECTUPPER(Name) FROMCustomer WHERENameLIKE'A%' ORDERBYName Supongamos queremos hacer una consulta simple SELECTUPPER(Name)FROM ( SELECT*, RN =row_number() OVER (ORDERBYName) FROMCustomer WHERENameLIKE'A%' ) A WHERE RN BETWEEN 21 AND 30 ORDERBYName Ahora supongamos que estos resultados están alimentando una página web y queremos obtener solo las filas 21-30. De la nada, ahora necesitamos una subquery
POR QUÉ LINQ VENCE A SQL SELECTTOP 10 UPPER(c1.Name) FROMCustomer c1 WHERE c1.Name LIKE'A%' AND c1.ID NOTIN ( SELECTTOP 20 c2.ID FROMCustomer c2 WHERE c2.Name LIKE'A%' ORDERBY c2.Name ) ORDERBY c1.Name Y si necesitamos agregar soporte para bases de datos anteriores a SQL SERVER 2005, se vuelve peor aún!! No solo es complicado, sino que viola el principio DRY (Don’tRepeatYourself)
POR QUÉ LINQ VENCE A SQL SELECTTOP 10 UPPER(c1.Name) FROMCustomer c1 WHERE c1.Name LIKE'A%' AND c1.ID NOTIN ( SELECTTOP 20 c2.ID FROMCustomer c2 WHERE c2.Name LIKE'A%' ORDERBY c2.Name ) ORDERBY c1.Name varquery = from c indb.Customers wherec.Name.StartsWith("A") orderbyc.Name selectc.Name.ToUpper(); varthirdPage = query.Skip(20).Take(10); Aquí tenemos la misma consulta pero en LINQ. La ganancia en simplicidad es clara. IQueryable<T> Paginate<T> (thisIQueryable<T> query, intskip, inttake) { returnquery.Skip(skip).Take(take); } varthirdPage = query.Paginate (20, 10); Composability: Podemos dividir la consulta y hacer métodos genéricos reutilizables
SELECTp.* FROMPurchase p LEFTOUTERJOIN Customer c INNERJOINAddress a ONc.AddressID= a.ID ONp.CustomerID= c.ID WHERE (a.State='WA'||p.CustomerIDISNULL) AND p.ID in ( SELECTPurchaseIDFROMPurchaseItem GROUPBYPurchaseIDHAVINGSUM(SaleAmount)> 1000 ) Otro beneficio de LINQ es que puedes consultar a través de relaciones sin tener que hacer joins. varpurchases = from p indb.Purchases wherep.Customer.Address.State == "WA“ ||p.Customer == null wherep.PurchaseItems.Sum(pi => pi.SaleAmount) > 1000 select p;
Parametrización: No hay que complicarse con los ataques de inyección de SQL pues la parametrización de LINQ es inline, segura y altamente legible. IQueryable<Customer> GetCustomers (stringstate, decimal? minPurchase) { varquery = Customers.AsQueryable(); if (state != null) query = query.Where (c => c.Address.State == "WA"); if (minPurchase != null) query = query.Where (c => c.Purchases.Any (p => p.Price > minPurchase.Value)); returnquery; } SELECT [t0].[ID], [t0].[Name], [t0].[AddressID] FROM [Customer] AS [t0] Si pasamos state y minPurchase nulos SELECT [t0].[ID], [t0].[Name], [t0].[AddressID] FROM [Customer] AS [t0] LEFTOUTERJOIN [Address] AS [t1] ON [t1].[ID] = [t0].[AddressID] WHERE (EXISTS( SELECTNULLAS [EMPTY] FROM [Purchase] AS [t2] WHERE ([t2].[Price] > @p0)AND([t2].[CustomerID] = [t0].[ID]) ))AND([t1].[State] = @p1) Si pasamos ambos valores LINQ no solo agregará los predicados, sino que también los JOINS
Cuándo no usar LINQ A pesar de su poder, LINQ no deja obsoleto a SQL. Toma más del 95% de la funcionalidad de las queries, pero se seguirá necesitando SQL para: • Queries que busquen máxima optimización. • Queries que involucren seleccionar en tablas temporales y luego consultar esas tablas. • Actualizaciones con predicados e inserciones masivas (bulk) • Triggers
Tener que conocer dos lenguajes para querys no es realmente un problema, dado que de todas maneras LINQ provee una forma común para interactuar con distintas fuentes de datos. Arreglos, Listas, XML, Bases de Datos, y en general, de cualquier objeto que herede de IQueryable y IEnumerable.
Fuentes • http://msdn.microsoft.com/en-us/library/bb397933.aspx • http://msdn.microsoft.com/en-us/library/bb397926.aspx • http://www.codeproject.com/Articles/230380/LINQ-to-SQL-Advanced-Concepts-and-Features • http://www.linqpad.net/WhyLINQBeatsSQL.aspx