LINQ y LINQ para SQL

viernes, 1 de febrero de 2008

Un par de meses después de la liberación pública del Microsoft .NET Framework 3.5 (y su plataforma de desarrollo preferida, Visual Studio 2008), es buen momento para presentar algunas de nuestras impresiones sobre lo que probamos para el uso de estas tecnologías en aplicaciones reales.

LINQ y sus providers

El Language INtegrated Query (consultas integradas al lenguaje) consiste en un conjunto de extensiones introducidas en el runtime de .NET y sus lenguajes principales (C# y VB) que permiten implementar una sintaxis flexible de consulta, y de paso varias cosas más.

La aplicación de LINQ a diversas fuentes de datos, tales como colecciones en memoria, bases de datos relacionales, documentos de estructura jerárquica (XML) y otras, depende de la disponibilidad de los "providers" específicos para ese tipo de origen de datos.

Por eso, al analizar las capacidades de LINQ hay que distinguir entre la tecnología (o sintaxis) LINQ genérica, y los distintos proveedores específicos (LINQ to SQL, LINQ to XML, LINQ to DataSet, etc.) que pueden encontrarse en distinto grado de evolución. Vamos a analizarlos por separado:

LINQ

Una de las ventajas que inmediatamente resaltan al empezar a usar sintaxis LINQ en las aplicaciones, es la enorme simplificación que significa usar una sola sintaxis (una sola API) para operar sobre colecciones absolutamente heterogéneas. Hace unos meses yo conocía perfectamente el método Sort -específico de la clase Array- que permite ordenarlos; una propiedad Sort -en los DataView- que con otra sintaxis logra el mismo efecto sobre las vistas de un datatable. Y recurria a la ayuda en línea cuando necesitaba ordenar un conjunto de nodos XML o cualquier otra cosa. Lo mismo para filtrar, etc.

Felizmente ya me estoy olvidando de todo eso, porque ahora sólo uso expresiones como estas, independientemente de cuál es la coleccion sobre la que opero:

var pedidos = from a in archivos
where a.Extension == ".xml"
order by a.Name
select a;

O su equivalente, no tan natural para leer pero más revelador de lo que ocurre tras la escena:

var pedidos = archivos
.Where(a => a.Extension == ".xml")
.OrderBy(a => a.Name)
.Select(a => a);"

Por supuesto, en ambos casos dejo que el Intellisense haga la mayor parte del trabajo.

Las extensiones que permiten esta sintaxis, como la declaracion anónima de tipos (new { Edad = m.edad, Nombre = ... }) y los métodos de extensión (ej. .Where(), .Select(), etc) tambien hacen que todo el manejo de colecciones propias y de clases de negocio representadas como objetos "custom" sea muchísmo mas fácil y abreviado.

Hasta acá, no hay ninguna duda. Esto es para usarlo, cuanto antes, y no hay retorno.

NOTA: El segundo ejemplo trae reminiscencias de los paradigmas de programación funcional, y eso es exactamente lo que se ha incorporado al runtime .NET, mediante las expresiones lambda (otra de las extensiones incluidas en la nueva versión).

LINQ para SQL

Acá el paisaje es muy atractivo, pero hay que estar atento al camino que empieza a volverse espinoso.

Lo primero que uno nota es que LINQ para SQL está integrado por distintos componentes, algunos de los cuales son más deseables (o están más maduros en su evolución) que otros.

  • Existe un O/R designer (diseñador Objeto / Relacional), integrado en la IDE de Visual Studio, que permite mapear visualmente las tablas, procedimientos almacenados, etc. de un SQL Server y genera un archivo .DBML (XML) con su estructura.

  • Hay una herramienta de generación de código ("custom tool") tambien integrada en la IDE, que a partir de ese "mapa" DBML genera código de clases, decoradas con atributos de LINQ, que permiten el posterior armado de consultas LINQ

  • Las clases generadas se integran con un "Data Context" y otras clases del nuevo namespace System.Data.Linq, que incluyen la lógica de acceso a datos (sin necesidad de utilizar explícitamente las clases de ADO.NET) para traer los objetos de la BD y para persistir los cambios, en una modalidad "conectada" que no siempre resulta la más apropiada.

  • Finalmente, existe un "provider" de LINQ para SQL que, en base a los atributos de las clases, convierte la consulta LINQ en una sentencia Transact-SQL para enviar al servidor

  • Para los primeros dos componentes enumerados en esta lista(que se integran en la IDE) existe una alternativa como comando de línea (SqlMetal.exe) que tiene una funcionalidad similar pero no idéntica.

En proximos artículos del blog avanzaremos más sobre las características y escenarios de uso de LINQ para SQL. Por ahora, es importante entender la distincion entre la tecnología LINQ en general -de indudable aplicación- y su actual implementación para SQL, que tiene claros y oscuros.