Posted by: carloslone | August 7, 2008

LINQ in Action Chapter 1 Book Review (Que es LINQ?)

linq in Action

Estimados Compañer@s:

Recientemente hemos logrado tener el apoyo en la comunidad de Manning, a cambio algunos ofrecimos colaborar con Book Reviews de los libros de .net.

He decidido ir haciendo el review del libro "LINQ in Action" por capítulos e ir trasladándoles a ustedes el conocimiento adquirido!, así que es suficiente y comenzamos con el primer capítulo "Introducción a Linq"

Básicamente en este capítulo nos encontraremos con la definición de LINQ(Language Integrated Query), sus orígenes, su visión y el por que fue integrado al .net Framework. Comenzaré este post explicando un poco el por que de LINQ.

Como programadores sabemos que el software es algo simple, ya que lo podríamos reducir a dos cosas: Código y datos. Sin embargo, escribir software no es tan simple y una de las mayores actividades que envuelve el escribir código es trabajar con datos.

Normalmente como desarrolladores tenemos la necesidad de tener que conocer, y no solo conocer sino realmente ser buenos, en diferentes lenguajes y tecnologías cuando desarrollamos una aplicación, tal es el caso que no solo necesitamos utilizar un lenguaje de programación, sino también conocer de SQL y algunas veces API’s para trabajar con documentos en XML.

Que es LINQ?

En el esquema actual supongamos que tenemos que escribir una aplicación, la posibilidad que tengamos que hacer persistir objetos hacia la base de datos es muy alta, así como enviar consultas a la base de datos y cargar esos resultados en objetos. Esta es una tarea que normalmente consume bastante tiempo al desarrollador de aplicaciones y el problema principal es que existe una brecha entre los lenguajes de programación y las bases de datos.

Los motivos principales originales detrás de LINQ fueron administrar las dificultades conceptuales y técnicas al momento de trabajar con bases de datos y lenguajes de programación de .net. Pero, realmente la intención de Microsoft fue proveer una solución para el problema del "mapeo relacional de objetos" (ORM en ingles), así como simplificar la interacción entre objetos y fuentes de datos. LINQ evoluciono hacia un conjunto de herramientas integradas para consultas. Estas herramientas pueden ser utilizadas para acceder a información almacenada en objetos en memoria (LINQ to Objects), bases de datos (LINQ to SQL) , documentos XML (LINQ to XML), un sistema de archivos o cualquier otra fuente. Veamos la siguiente gráfica:

Arquitectura Linq

Como vemos en la gráficas anterior, LINQ es una tecnología que nos puede ayudar mucho a resolver los problemas que se presentan para hacer consultas hacia fuentes de datos, noten que LINQ es extensible y de hecho hoy en día hay muchas implementaciones de linq hacia otras fuentes de datos o servicios. Un factor clave de LINQ es que fue diseñado para ser utilizado contra cualquier tipo de objeto o fuente de datos y para proveer un modelo de programación consistente.

Otra característica importante de LINQ es que al utilizarlo se trabaja en un mundo fuertemente tipado (Strongly Typed), lo que permite tener verificaciones en tiempo de compilación para las consultas, así como la asistencia del Intellisense de Visual Studio.

Por que necesitamos LINQ?

Cualquiera que ya halla trabajado en .net podría argumentar lo siguiente: si ya tengo un modelo de acceso a datos con ADO.NET y a través del mismo puedo hacer mis consultas y actualizaciones de datos por que necesito LINQ?, para dar respuesta a esto enumeremos a continuación algunos de los problemas mas comunes con este escenario:

  • Generalmente los Queries están expresados como cadenas de datos (strings), lo que significa que estos sobrepasan cualquier tipo de chequeo en tiempo de compilación. Que pasaría si el nombre de una columna fue escrito erróneamente?, que pasaría si el nombre de una columna es renombrado?
  • Generalmente no nos preocupamos por utilizar Ansi SQL al hacer nuestras consultas, lo cual no nos garantiza que al tener que cambiar de base de datos nuestra consulta no tendrá problemas.
  • Cuando se habla de Object Relational Mappers (ORM’s) generalmente se hace referencia al termino "impedance mismatch", que se resume a la siguiente expression Datos != Objetos y mas especificamente Datos Relacionales != Objetos. Ambos paradigmas son totalmente diferentes.
  • Existen diferentes ORM’s en el mercado, ya sea open source o comprados, pero el problema principal es que utilizan métodos diferentes para solucionar el "impedance mismatch" o bien requieren de hacer mapeos por archivos XML entre las entidades de base de datos y objetos POCO (Plain Old Clr Object), tal es el caso de Nhibernate.

Aquí es donde LINQ entra al rescate, en primer lugar con LINQ trabajamos en un ambiente fuertemente tipado, lo cual nos garantiza que alguno cambio en la fuente de datos, inmediatamente tendremos los warnings del compilador. Los programadores no se tendrán que preocupar con las sentencias SQL que se deben enviar a la base de datos, ya que este trabajo de traducción lo maneja automáticamente LINQ. Por ultimo utilizamos un esquema de programación consistente, lo que significa que no importa a que fuente de datos vamos a realizar la consulta, la sintaxis siempre es la misma.

HELLO WORL LINQ

Bueno, para terminar esta primer capítulo veamos un poco de código. Al final a muchos nos aburre la teoría y preferimos las cosas prácticas. Ok, a continuación realizaremos nuestra primer consulta con LINQ, se trata de nuestro viejo amigo "Hello World".

Que necesitan tener instalado para usar LINQ? pueden utilizar VS2008, o algunas de las versiones express como Visual Web Developer Express 2008 y por su puesto tener instalado el .net framework 3.5.

Veamos el siguiente código que nos demuestra el uso de Linq to objects, en el cual crearemos una lista de strings y obtendremos las palabras con mas de 4 letras:

   1: private static void EjemploConLinq()
   2:         {
   3:             string[] palabras = {"Guatemala", "Pais", "Eterna", "Primavera", "Hermosa","El"};
   4:  
   5:             var consulta = from p in palabras
   6:                            where p.Length >= 4
   7:                            select p;
   8:  
   9:             foreach (var palabra in consulta)
  10:             {
  11:                 Console.WriteLine(palabra);
  12:             }
  13:         }

VB.NET

   1: Private Sub EjemploConLinq()
   2:         Dim palabras() As String = {"Guatemala", "Pais", "Eterna", "Primavera", "Hermosa", "El"}
   3:  
   4:         Dim consulta = From p In palabras _
   5:                        Where p.Length >= 4 _
   6:                        Select p
   7:  
   8:         For Each p In consulta
   9:             Console.WriteLine(p)
  10:         Next
  11:     End Sub

Si se dan cuenta hay algunos aspectos nuevos que estamos utilizados y que realmente no todo tiene que ver con LINQ, por ejemplo la palabra "var" o "Dim" sin tipo (vb.net) sirve para poder definir variables sin tener que especificar el tipo de dato de la misma, este es un feature de C#3 y Vb 9 llamado Type Inference. Luego viene la consulta, si se dan cuenta es muy parecida a una sentencia de SQL. Por el momento no se preocupen por la sintaxis, más adelante en otro post veremos a detalle la misma, lo importante es observar lo simple y consistente que es el modelo de programación. Pero esperen, como se miraría este código sin linq?, veamoslo

   1: private static void EjemploSinLinq()
   2:         {
   3:             string[] palabras = { "Guatemala", "Pais", "Eterna", "Primavera", "Hermosa", "El" };
   4:  
   5:             foreach (string p in palabras)
   6:             {
   7:                 if (p.Length>=4)
   8:                     Console.WriteLine(p);
   9:             }
  10:         }

VB.NET

   1: Private Sub EjemploSinLinq()
   2:         Dim palabras() As String = {"Guatemala", "Pais", "Eterna", "Primavera", "Hermosa", "El"}
   3:  
   4:         For Each p As String In palabras
   5:             If p.Length >= 4 Then _
   6:                 Console.WriteLine(p)
   7:         Next
   8:     End Sub

Esperen un momento…. Al parecer el EjemploSinLinq contiene menos líneas de código y se ve más fácil, entonces?, bueno no se desanimen, para poder ver el poder de linq ahora hagamos el siguiente ejemplo: Listas los valores de la lista del ejemplo anterior agrupado por largo de la cadena y ordenado descendentemente y las palabras ascendentemente:

   1: private static void EjemploLinqConGrupos()
   2:         {
   3:             string[] palabras = { "Guatemala", "Pais", "Eterna", "Primavera", "Hermosa", "El" };
   4:  
   5:             var consulta = from p in palabras
   6:                            orderby p ascending 
   7:                            group p by p.Length into GrupoPorLongitud
   8:                            orderby GrupoPorLongitud.Key descending 
   9:                            select new {Length= GrupoPorLongitud.Key, Palabra=GrupoPorLongitud};
  10:             
  11:             foreach (var grupo in consulta)
  12:             {
  13:                 Console.WriteLine("Palabra con logitud {0}",grupo.Length);
  14:                 foreach (var palabra in grupo.Palabra)
  15:                 {
  16:                     Console.WriteLine("  "+palabra);    
  17:                 }
  18:                 
  19:             }
  20:         }

VB.NET

   1: Private Sub EjemploLinqConGrupos()
   2:     Dim palabras() As String = {"Guatemala", "Pais", "Eterna", "Primavera", "Hermosa", "El"}
   3:  
   4:     Dim consulta = From p In palabras _
   5:                    Order By p Ascending _
   6:                    Group By p.Length Into GrupoPorLongitud = Group _
   7:                    Order By Length Descending
   8:  
   9:     For Each p In consulta
  10:         Console.WriteLine("Palabra con logitud {0}", p.Length)
  11:         For Each palabra In p.GrupoPorLongitud
  12:             Console.WriteLine("  " + palabra)
  13:         Next
  14:     Next
  15: End Sub

Como ven con LINQ una tarea muy sencilla, les dejo de tarea realizar esta operación sin el uso de LINQ (en el área de comentarios pueden postear su solución). Verán que esta en realidad se convierte en una tarea más complicada.

Ahora que hemos visto nuestro primer ejemplo es hora de ver el poder de LINQ para trabajar con XML, supongamos que tenemos un que armar un documento XML con información de clientes para esto definiremos una clase Cliente:

   1: class Cliente
   2:     {
   3:         public int idCliente { get; set; }
   4:         public string NombreCliente { get; set; }
   5:         public string Pais { get; set; }
   6:  
   7:         public Cliente(int id, string nombre, string pais)
   8:         {
   9:             idCliente = id;
  10:             NombreCliente = nombre;
  11:             Pais = pais;
  12:         }
  13:     }

VB.NET

   1: Public Class Cliente
   2:  
   3:     Private _idCliente As Integer
   4:     Public Property idCliente() As Integer
   5:         Get
   6:             Return _idCliente
   7:         End Get
   8:         Set(ByVal value As Integer)
   9:             _idCliente = value
  10:         End Set
  11:     End Property
  12:  
  13:  
  14:     Private _nombreCliente As String
  15:     Public Property nombreCliente() As String
  16:         Get
  17:             Return _nombreCliente
  18:         End Get
  19:         Set(ByVal value As String)
  20:             _nombreCliente = value
  21:         End Set
  22:     End Property
  23:  
  24:  
  25:     Private _pais As String
  26:     Public Property Pais() As String
  27:         Get
  28:             Return _pais
  29:         End Get
  30:         Set(ByVal value As String)
  31:             _pais = value
  32:         End Set
  33:     End Property
  34:  
  35:     Public Sub New(ByVal id As Integer, ByVal nombre As String, ByVal paisCliente As String)
  36:         _idCliente = id
  37:         _nombreCliente = nombre
  38:         _pais = paisCliente
  39:     End Sub
  40:  
  41:  
  42: End Class

Ahora supongamos que vamos a tener una colección de objetos tipo cliente y queremos obtener los clientes cuyo país sea igual a Guatemala y lo queremos mostrar en un documento XML con el siguiente formato:

   1: <clientes>
   2:     <cliente id="1" nombre="Carlos Lone">
   3:         <pais>Guatemala</pais>
   4:     </cliente>
   5:     <cliente id="2" nombre="Juan Perez">
   6:         <pais>Guatemala</pais>
   7:     </cliente>
   8:     <cliente id="1" nombre="Bill Gates">
   9:         <pais>Guatemala</pais>
  10:     </cliente>
  11: </clientes>

Entonces veamos a continuación el ejemplo para generar este documento de XML haciendo uso de LINQ:

   1: private static void GeneraColeccionClientes()
   2:         {
   3:             var clientes = new List<Cliente>();
   4:             clientes.Add(new Cliente(1, "Carlos Lone", "Guatemala"));
   5:             clientes.Add(new Cliente(2, "Juan Perez", "Guatemala"));
   6:             clientes.Add(new Cliente(3, "Bill Gates", "Guatemala"));
   7:             clientes.Add(new Cliente(4, "Fidel Castro", "Cuba"));
   8:  
   9:             // Generamos el Documento XML
  10:             XElement xml = new XElement("clientes",
  11:                 from cliente in clientes
  12:                 where cliente.Pais == "Guatemala"
  13:                 select new XElement("cliente",
  14:                     new XAttribute("id", cliente.idCliente),
  15:                     new XAttribute("nombre", cliente.NombreCliente)
  16:                     )
  17:                    );
  18:             Console.WriteLine(xml);
  19:         }

VB.NET

   1: Private Sub GeneraColeccionClientes()
   2:         Dim clientes As New List(Of Cliente)
   3:         clientes.Add(New Cliente(1, "Carlos Lone", "Guatemala"))
   4:         clientes.Add(New Cliente(2, "Juan Perez", "Guatemala"))
   5:         clientes.Add(New Cliente(3, "Bill Gates", "Guatemala"))
   6:         clientes.Add(New Cliente(4, "Fidel Castro", "Cuba"))
   7:  
   8:         Dim xml As New XElement("clientes", _
   9:                                 From cliente In clientes _
  10:                                 Where cliente.Pais = "Guatemala" _
  11:                                 Select New XElement("cliente", _
  12:                                                     New XAttribute("id", cliente.idCliente), _
  13:                                                     New XAttribute("nombre", cliente.nombreCliente) _
  14:                                                     ) _
  15:                                                     )
  16:         Console.WriteLine(xml)
  17:     End Sub

Podemos observar claramente en este ejemplo la consistencia del modelo de programación que define LINQ, es decir vemos que la forma de realizar una consulta tiene la misma estructura. Otro factor importante es notar el uso de las clases XElement y XAttribute, las cuales pertenecen al namespace System.Xml.Linq, con las mismas la generación del documento XML es mucho más sencilla. Nuevamente les dejo la inquietud de implementar esta operación haciendo uso de las clases tradicionales para manejo de XML que tiene el framework sin usar LINQ.

Un momento ….! , hay más …. SI, esta es una buena noticia para los fanáticos de VB.NET, uno de los features de VB 9 es la capacidad de utilizar XML Literals, a través de los cuales la generación de documentos XML se facilita mucho más. Xml Literals utiliza el principio de generación de código dinámico utilizado en las paginas ASP tradicionales, por medio de la utilización de expresiones <%= %> veamos el ejemplo

VB.NET

   1: Private Sub GeneraColeccionClientesConXMLLiterals()
   2:         Dim clientes As New List(Of Cliente)
   3:         clientes.Add(New Cliente(1, "Carlos Lone", "Guatemala"))
   4:         clientes.Add(New Cliente(2, "Juan Perez", "Guatemala"))
   5:         clientes.Add(New Cliente(3, "Bill Gates", "Guatemala"))
   6:         clientes.Add(New Cliente(4, "Fidel Castro", "Cuba"))
   7:  
   8:         Dim xmlDoc As XElement = _
   9:             <clientes>
  10:                 <%= From cliente In clientes _
  11:                     Where cliente.Pais = "Guatemala" _
  12:                     Select _
  13:                     <cliente id=<%= cliente.idCliente %> nombre=<%= cliente.nombreCliente %>/> _
  14:                 %>
  15:             </clientes>
  16:  
  17:         Console.WriteLine(xmlDoc)
  18:     End Sub

Vemos que esta es una forma más legible y fácil para poder crear documentos XML, esta característica funciona únicamente en VB.NET.

Tenemos pendiente ver LINQ to SQL, pero este tema lo dejare para el próximo post.

Esten Pendientes.

CONCLUSION

LINQ es una tecnología que ha venido a facilitar a los desarrolladores, para utilizar un modelo consistente de programación para realizar consultas. La constante necesidad de administrar la información en una aplicación obliga a los desarrolladores a tener que volverse expertos en diferentes lenguajes y api’s para manejar bases de datos, documentos XML u otra fuente de datos, LINQ permite unificar un mismo criterio para administrar este tipo de operaciones y uno de sus principales objetivos de diseño fue proveer una arquitectura extensible para que pudieran generarse nuevas implementaciones a otras fuentes de datos.

LINQ en el .net framework 3.5 viene con 4 sabores:

  • Linq to Objects
  • Linq to SQL
  • Linq to XML
  • Linq to Dataset

Aunque ya se han implementando mas fuentes de datos para trabajar con esta tecnología

Este post ha resumido muchos de los aspectos expuestos en el capitulo 1 del libro LINQ IN ACTION el cual se los recomiendo, ya que es claro, conciso y práctico.

Esten pendientes de los siguientes capitulos !

Saludos,

Carlos A. Lone

P.D. Les comparto los dos proyectos utilizados en este post (C# y VB.NET):

Ejemplo C#

Ejemplo en VB.NET

Etiquetas de Technorati: ,,,

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Categories

%d bloggers like this: