Blog del CIIN

Blog del Centro de Innovación en Integración de Cantabria
Comenzando con LINQ: Bases y Consulta de Datos en Memoria!

Como os comentaba en un post previo, uno de los cometidos como integrantes de un centro de innovación de Microsoft es estar al día de las últimas novedades en las que Microsoft está trabajando, conocer en detalle dichas novedades, cacharrear con ellas, etc, siempre teniendo en mente que resulta realmente complicado seguir el ritmo de creación de Microsoft. Por este motivo, nos planteamos mes a mes que tecnologías sería interesante conocer para transmitir el conocimiento a las empresas de Cantabria y ponerlas en la parrilla de salida hacía las futuras tendencias tecnológicas. Pues bien, una de las últimas tecnologías que hemos estado probando es LINQ, y francamente estoy sorprendido tanto por sus características (construida sobre las innovaciones de lenguaje de C# y VB 9.0) como por sus prestaciones: habilitar el uso de consultas a objetos de memoria, orígenes de datos, XML o cualquier otro “ente” que se nos ocurra (a partir de la capacidad de extensibilidad de LINQ).

Para los nuevos en la materia, LINQ o Language Integrated Query es un framework de consultas que habilita el uso de órdenes tipo SQL integradas en el lenguaje de programación a partir de una serie de operadores estándar de consulta que permiten realizar consultas sobre cualquier colección de tipo IEnumerable<T>. La arquitectura de LINQ es la siguiente:

¿Qué proporciona LINQ?

Antes de entrar en materia, no está de más tener claro que ventajas o características nos da LINQ. Destacaría las siguientes:

·         Un framework unificado de acceso a objetos, datos y XML. Y que además es completamente extensible.

·         Consultas tipo SQL en código C# y VB:

o   Sintaxis potente, similar a T-SQL.

o   La curva de aprendizaje es reducida.

·         Comprobación de tipos e intellisense.

·         Modelo de proveedores extensible, ya se han definido extensiones hacia SQL (LINQ To SQL) y XML (LINQ to XML).

·         Una serie de operadores estándar de consulta out-of-the-box, que permiten definir operaciones de recorrido, filtro y proyección de modo declarativo en el lenguaje.

·         ¿Se os ocurren más?

Bueno, después de esta pequeña introducción a LINQ (para más información, os recomiendo que vayáis al sitio oficial del proyecto LINQ), es hora de pasar a la acción. También es recomendable la información y ejemplos que en el sitio de El Guille han colgado tanto Guillermo Som como Octavio Hernández  En este post comentaré algunas de las innovaciones del lenguaje (para C#) conocidas, así como el modo de definir consultas integradas en el lenguaje contra un objeto de memoria.

C# 3.0: Innovaciones en el lenguaje

Como comentábamos, LINQ se basa en muchas de las innovaciones del lenguaje que viene con C# 3.0 y VB 9.0. Antes de empezar con las innovaciones, seguro que alguno os está preguntando que se necesita para poder probarlas:

·         Evidentemente, Visual Studio 2005 (No necesitáis bajaros la última CTP de Orcas).

·         LINQ Preview para VB y C# de Mayo de 2006 (no he encontrado una versión posterior para poder utilizarla con VS 2005, pero para el propósito de este post es suficiente), que os podéis descargar en este enlace. Al instalar esta Preview, veréis que además de las correspondientes plantillas de proyecto, se instalarán un montón de ejemplos y HandOn labs tanto para VB como C#.

Una vez instalada la preview, si os vais a VS 2005 veréis que aparece una nueva entrada en los tipos de proyectos: LINQ Preview con las correspondientes plantillas añadidas.

Tras pulsar OK, nos saldrá un mensaje advirtiéndonos que este tipo de proyecto se refiere a una versión no soportada de C# 3.0 y que ciertas funcionalidades podrían no funcionar de manera correcta. Corremos el riesgo, y ya estamos listos para empezar a ver las innovaciones en el lenguaje, las cuales están disponibles (no tenéis más que examinar las referencias que se añaden al proyecto)  a través de los siguientes espacios de nombres:

·         using System.Query;

·         using System.Xml.XLinq;

·         using System.Data.DLinq;

·         using System.Expressions; (está la tenemos que añadir para poder crear árboles de expresión como luego veremos).

Entre estas innovaciones son destacables las siguientes

·         Declaración implícita de tipos, lo que implica que cuando declaramos un objeto no es necesario que especifiquemos su tipo, sino que el compilador es capaz de inferirlo de manera dinámica en tiempo de compilación a partir del valor estático asignado. La clave de la declaración de tipos implícitos está en el uso de la palabra reservada var. En la práctica, esta innovación facilita poder referenciar en nuestro código instancias de tipos anónimos. Veamos un ejemplo de declaración implícita de tipos.

            //Declaración ímplicita de tipos

            var numero=2;

            var cadena="Hola mundo desde LINQ!";

 

            Console.WriteLine("numero es de tipo " + numero.GetType()

                                + ".El valor de numero es " + numero);

            Console.WriteLine("cadena es de tipo " + cadena.GetType()

                                + ".El valor de cadena es " + cadena);

            Console.ReadLine();

 La salida por pantalla que obtendríamos para este caso es:

La ventaja que nos aporta esta innovación es que libera al desarrollador de tener que definir de manera explícita los tipos que necesite  al programar una aplicación. Esta característica es clave para LINQ, puesto que el desarrollador no necesita definir los tipos que va a devolver una consulta, sino que es el compilador quien dinámicamente va a realizar esta tarea.

·         Tipos anónimos, esta característica permite crear objetos de tipo anónimo, es decir, de nuevo podemos omitir el tipo cuando instanciamos un objeto y este es construido de manera dinámica en tiempo de compilación. Además de poder definir un objeto de manera anónima, es posible definir propiedades asociadas al mismo. Un ejemplo de esta innovación es el siguiente:

            var Santander=new {NombreCiudad="Santander", PoblacionCiudad=180000};

            Console.WriteLine("La ciudad de " + Santander.NombreCiudad + " tiene una población de " +

                                Santander.PoblacionCiudad + " habitantes");

            Console.ReadLine();

            Console.WriteLine("Santander es de tipo " + Santander.GetType());

            Console.ReadLine();

 En este caso, la salida por pantalla es la siguiente:

Como vemos, aunque hemos declarado un tipo anónimo, el compilador es capaz de inferir el tipo correspondiente y sacar por pantalla los valores de sus propiedades. También vemos que el tipo devuelto es <Projection>f __0 que es el que se infiere en tiempo de compilación.  Si miramos el ensamblado a través de la utilidad reflector, tendremos más información respecto al tipo generado en tiempo de compilación.

 

·         Inicializadores de objetos, esta innovación ya la vimos en la anterior. Lo que permite es inicializar objetos (anónimos o no) en el momento en que los instanciamos.

public class Ciudad

        {

            public string NombreCiudad;

            public int PoblacionCiudad;

        }

        static void Main(string[] args)

        {

 

            Var Santander=new Ciudad{NombreCiudad="Santander",

                                        PoblacionCiudad=180000};

            Console.WriteLine("La ciudad de " + Santander.NombreCiudad +

                                               " tiene una población de " +

                                                Santander.PoblacionCiudad + " habitantes");

            Console.ReadLine();

            Console.WriteLine("Santander es de tipo " + Santander.GetType());

            Console.ReadLine();

        }

En este caso, en el código estamos combinando la declaración implícita de tipos y la inicialización de objetos. Por lo que ahora, el tipo devuelto es Ciudad.

·         Métodos de extensión, o dicho de otra forma: mecanismos que habilitan la extensión de objetos. La base de esta innovación consiste en crear clases de extensión que nos permitan extender la funcionalidad de tipos existentes a partir de crear nuevos métodos. Los métodos de extensión son métodos estáticos que son  habilitados como métodos de extensión a través de la palabra reservada this.

 

 static class ExtensionDeTipos

        {

            public static string Saludar(this string nombre)

            {

                return ("Hola " + nombre + "!");

            }

 

 

        }

        static void Main(string[] args)

        {

           

            string nombre = "Mundo";

            Console.WriteLine(nombre.Saludar());

            Console.ReadLine();

 

        }

 

Mediante el código anterior, hemos definido una clase estática dentro de la cuál definiremos nuestros métodos de extensión. En este caso, estamos extendiendo nombre que es de tipo cadena mediante el método Saludar y como vemos la clave de esta extensibilidad es la palabra reservada this.

Una característica interesante de los métodos de extensión es que se pueden añadir a cualquier tipo, incluyendo tipos genéricos como List <T> y Dictionary <T>.

 

·         Expresiones lambda, que habilitan el uso de condiciones sin tener que especificar el tipo. En la práctica, las expresiones lambda permiten definir de un modo más claro y directo los métodos anónimos de C # 2.0 (quizás esta es una de las innovaciones más destacadas de C# 3.0 y una de las bases de LINQ junto con los métodos de extensión). Para entender esta innovación, no está de más recordar que es un método anónimo en C# 2.0:

List <string> NombresLongitudMayor5=nombres.FindAll(delegate(string s)

                                                                       {return(s.Length)>=5;});

       

Pues bien, la expresión anterior se puede escribir de manera más directa en C# 3.0 utilizando una expresión lambda, que unida a otras innovaciones simplifica mucho el código anterior

var NombresLongitudMayor5=nombres.FindAll(s => s.Length>=5);

 

Como vemos, una expression lamba consta de tres elementos:

o   Un parámetro de lista (s), que puede ser tipado de manera explícita o implícita. En el ejemplo, de nuevo estamos utilizando tipado implícito.

o   El token =>.

o   La expresión a aplicar (la longitud sea 10).

Un ejemplo completo de uso de expresiones lambda sería el siguiente:

var nombres=new List<string>();

            nombres.Add("Luis");

            nombres.Add("Juan Carlos");

            nombres.Add("Pepe");

            nombres.Add("Ramón");

 

            var NombresLongitudMayor5=nombres.FindAll(s => s.Length>=5);

            foreach(string nombre in NombresLongitudMayor5)

            {

                Console.WriteLine(nombre);

            }

            Console.ReadLine();

 

·         Árboles de expresión, que son representaciones más eficientes en memoria de una expresión lambda. La idea de los árboles de expresión es dar una visión más transparente e implícita que el código IL, además de habilitar la utilización de expresiones lambda como datos en tiempo de ejecución. La clave de la definición de árboles de expresión está en un nuevo tipo: Expression <T>. Veamos un ejemplo:

Expression<Func<string,bool>> NombresLongitudMayor5= s => s.Length>=5;

 Console.WriteLine(NombresLongitudMayor5);

 Console.ReadLine();

         Código que produce la siguiente salida:

Como vemos, el árbol de expresión nos permite traducir la expresión lambda a datos que son manipulables. Pero, ¿Para qué nos sirven los árboles de expresión? Pues, y como se comenta en la documentación disponible del proyecto LINQ, para una implementación de acceso a base de datos, nos permitiría traducir los árboles a sentencias apropiadas para un tipo particular de BD. De hecho, esto es lo que se hace en LINQ to SQL (anteriormente DLinq), en el que los árboles de expresión son traducidos a sentencias T-SQL que puedan ser evaluadas en la BD.

LINQ to Objetcs: Consultas a objetos de memoria

Después de haber introducido algunas de las novedades del lenguaje que vendrán con C# 3.0 y de modo equivalente con VB y sobre las que se apoya LINQ, ya es hora de ver las posibilidades de LINQ en la práctica. Básicamente, LINQ utiliza estas innovaciones para definir habilitar el uso de consultas integradas en el lenguaje de programación. Para ello define una serie de operadores estándares de consulta que son métodos de extensión definidos sobre IEnumerable <T>, y cuyas características más relevantes son las siguientes:

·         Están construidos a partir de las innovaciones en el lenguaje vistas.

·         Permiten trabajar con datos en memoria. Esto es especialmente interesante para cuando trabajemos contra datos de una BD, de un archivo XML o cualquier otro origen de datos.

·         Las operaciones siempre se realizan en memoria.

Aquí os dejo el listado de los operadores estándar de consulta. Para conocer en detalle dichos operadores, os recomiendo la lectura de la traducción por Octavio Hernández del documento The LINQ Proyect. Este documento junto con otros también traducidos al castellano lo podéis encontrar aquí.

Tipo de Operador

Operador

Restricción

Where

Proyección

Select, SelectMany

Ordenación

OrderBy, ThenBy

Agrupamiento

GroupBy, Reverse, GroupJoin

Cuantificadores

Any, All

Particionado

Take, Skip, TakeWhile, SkipWhile

Conjuntos

Distinct, Union, Intersect, Except

Elementos

First, FirstOrDefault, ElementAt

Agregación

Aggregate,Count, Sum, Min, Max, Average

Conversión

ToArray, ToList, ToDictionary

Casting

OfType<T>

Join

Join, GroupJoin, On

 

Además del uso de los operadores estándar de consultas, LINQ utiliza otra innovación conocida como la evaluación diferida de consultas, que implica que una consulta no es realmente evaluada hasta el momento en que se itera con ella. La ventaja de esta técnica es que las consultas van a poder ser evaluadas múltiples veces.

Sin más, vamos a ver un ejemplo de LINQ contra objetos. El código sería el siguiente: 

        //Clase a partir de la cuál definiremos el objeto en memoria a consultar

        public class Ciudad

        {

            public string NombreCiudad;

            public int PoblacionCiudad;

 

        }

        static void Main(string[] args)

        {

         //Objeto en memoria sobre el que vamos a habiltiar la consulta

         var ciudades=new List<Ciudad>{

                        {NombreCiudad="Santander",PoblacionCiudad=180000},

                        {NombreCiudad="León",PoblacionCiudad=150000},

                        {NombreCiudad="Ponferrada",PoblacionCiudad=75000},

                        {NombreCiudad="Madrid",PoblacionCiudad=4000000}

         };

        //Consulta...

        var consulta=

                from c in ciudades

                where c.PoblacionCiudad>150000

                select new {c.NombreCiudad,c.PoblacionCiudad};

 

       Console.WriteLine("Ciudades con más de 150000 habitantes: ");

      //Aquí es dónde realmente se evalua la consulta...

        foreach(var c in consulta)

        {

            Console.WriteLine("Ciudad: {0}, Población {1}",

                            c.NombreCiudad,c.PoblacionCiudad);

        }

 

        Console.ReadLine();

 

En el código anterior hemos utilizado varias de las innovaciones vistas, a ver quién me las dice a partir de leer el post (así podré medir si me explico bien o no :P). La salida por pantalla sería la siguiente:

Bueno, pues hasta aquí el primer post que desde el CIIN hacemos de LINQ. Espero vuestros comentarios y respuestas a la dudilla planteada.

Published 13/2/2007 12:25 por Juan Carlos González Martín

Archivado en:

Comentarios

# re: Comenzando con LINQ: Bases y Consulta de Datos en Memoria!@ Tuesday, February 13, 2007 12:50 PM

Muy buen post.

Saludos!

Ezequiel Jadib

# re: Comenzando con LINQ: Bases y Consulta de Datos en Memoria!@ Tuesday, February 13, 2007 1:15 PM

Gracias Ezequiel!

Un saludo

JC

Juan Carlos González Martín

# re: Comenzando con LINQ: Bases y Consulta de Datos en Memoria!@ Tuesday, February 13, 2007 1:37 PM

Esta muy bueno este post,facil de entender

Romny

# LINQ To SQL: Definiendo un Modelo de Entidades y operando con él!@ Wednesday, February 21, 2007 1:00 PM

Después de unos días ajetreados preparando el seminario sobre LINQ que próximamente impartiremos en el

Blog del CIIN

# Linq To Sql. Por fin POO en acceso a datos&#8230; &laquo; Pasi??n Tecnol??gica@ Wednesday, February 28, 2007 9:02 PM

PingBack desde http://jordisanchez.wordpress.com/2007/02/28/linq-to-sql-por-fin-poo-en-acceso-a-datos/

Linq To Sql. Por fin POO en acceso a datos… « Pasi??n Tecnol??gica

# LINQ To XML: Integración de XML!@ Wednesday, March 07, 2007 5:50 PM

Como no podía ser de otra forma, y después de hablar de las bases de LINQ y de LINQ To SQL , desde el

Blog del CIIN

# LINQ To SQL: Query Visualizer!@ Sunday, April 29, 2007 11:22 PM

El otro día me comentaba Rodrigo Corral que le parecían interesantes muchos de los posts que tenemos

Blog del CIIN

# re: Comenzando con LINQ: Bases y Consulta de Datos en Memoria!@ Wednesday, October 10, 2007 3:16 PM

Hola espi!

Pues te comento, depende de en que entorno quieras jugar:

- Las pruebas de este post en concreto las hice con la CTP de LINQ que te puedes instalar sobre Visual Studio 2005. Esta CTP es de mayo de 2006:

www.microsoft.com/.../details.aspx

- Bajándote la Beta 2 de Visual Studio 2008 (más recomendable) que ya viene con LINQ plenamete integrado (ya tiene intellicence). Puedes bajarte el instalable e instalarlo en una máquina virtual (esto es lo que he hecho yo) o bien descargarte la máquina virtual que ya trae la instalación:

www.microsoft.com/.../details.aspx

Saludos

JC

Juan Carlos González Martín

# re: Comenzando con LINQ: Bases y Consulta de Datos en Memoria!@ Saturday, November 17, 2007 9:32 PM

Hace una semana inicie con LINQ y todas las novedades de VS2008 y la verdad que nos hacen las cosas mas facil, ahorrandonos el "trabajo sucio"  y lo mejor de todo es que nos da mas tiempo para idear mejores soluciones a los problemas comunes y solventar mas rapido los nuevos.. pronot pondre en mi espacio toas mis aventuras con VS2008.

Saludos!

Richard Karl

# re: Comenzando con LINQ: Bases y Consulta de Datos en Memoria!@ Monday, November 19, 2007 8:21 AM

Hola Richard!

Estupendo...chequearé tu blog para ver que novedades y cosas interesantes de VS 2008 nos cuentas...yo también publicaré alguna cosilla (ya he empezado hoy con workflows y Sharepoint).

Saludos

JC

Juan Carlos González Martín

# Visual Studio 2008 Beta2: Realizando Consultas con LINQ (I) &laquo;@ Thursday, February 28, 2008 11:22 AM

PingBack desde  Visual Studio 2008 Beta2: Realizando Consultas con LINQ (I) &laquo;

Visual Studio 2008 Beta2: Realizando Consultas con LINQ (I) «

# Extensibilidad de LINQ: LINQ Flavours! &laquo; Pasi??n por la tecnolog??a&#8230;@ Sunday, March 02, 2008 12:59 PM

PingBack desde  Extensibilidad de LINQ: LINQ Flavours! &laquo; Pasi??n por la tecnolog??a&#8230;

Extensibilidad de LINQ: LINQ Flavours! « Pasi??n por la tecnolog??a…

# Duda@ Wednesday, September 02, 2009 4:13 PM

Disculpneme, pero cual es la utilidad de utilizar LINQ....

Orlando

Deja tu comentario

(requerido) 
(requerido) 
(opcional)
(requerido)