jueves, 27 de mayo de 2010

Enlace a datos con Visual Studio .Net

Uno de los aspectos más importantes (por no decir el más importante) a la hora de ensamblar una aplicación de gestión es la técnica utilizada para enlazar dicha aplicación con la base de datos.

En el pasado el tipo de base de datos usado para guardar los datos persistentes de nuestra aplicación era crucial y debía ser cuidadosamente elegido antes de comenzar a transformar el proyecto en código. Desde que Visual Studio .Net apareció dicha elección ya no es tan crucial; los adaptadores de datos y la posibilidad de manejar tablas "desconectadas" nos ha permitido separar muy fácilmente la capa de datos de la lógica de la aplicación, lo que facilita a su vez la migración de un tipo de base de datos a otro, manteniendo intacta casi toda la codificación de nuestro proyecto.

Si bien el tipo de base de datos usado ya no es tan determinante, las últimas versiones de Visual Studio nos ofrecen un amplio abanico de opciones (DataSets, LINQ to SQL, Entity Framework, etc.) a la hora de conectar nuestra aplicación con dicha base de datos, lo cual nos genera un sinfín de dudas acerca de cuál de ellos es el mejor y el que debemos usar. Pues bien, en este artículo intentaré arrojar algo de luz para despejar dichas dudas, pero siempre desde mi experiencia como desarrollador, tratando de ofrecer, no una guía, sino una ayuda.

¿Cuál es la mejor técnica de enlace a datos (DataBinding)?: No hay una respuesta directa para esta pregunta. Todo depende del contexto en que se vaya a usar ese enlace y de las funciones que tendrá en cada caso (sólo lectura o con edición).

Empezaremos por describir las principales técnicas de enlace y sus cualidades e inconvenientes:
  • DataAdapter y DataSet. Nacen con Visual Studio .Net y suponen un gran salto desde el ADO o DAO que integraba Visual Studio 6.0. Proporcionan la posibilidad de manipular los datos de forma desconectada (cargados en memoria) y son fáciles de implementar. Actualmente se encuentran en desuso puesto que con la versión 2.0 de .Net Framework se introduce el siguiente de nuestros protagonistas:
  • Typed DataSet. Es una combinación de los dos anteriores en una sóla entidad, con la posibilidad de extender su funcionalidad con nuestro propio código. Facilita mucho más la implementación y resulta mucho más potente.
  • DataReader. Sólo permite una lectura secuencial de registros desde la base de datos. Por si mismo no es un método de enlace a datos, pero lo facilita. De hecho es la técnica que usan los TableAdapter para llenar un DataSet con datos. No obstante lo expongo como un método de enlace porque en el caso de extracción de informes (datos de sólo lectura) puede ser una opción muy a tener en cuenta.
  • LINQ to SQL. Basado en el lenguaje de consulta a datos introducido en la versión 3.5 de .Net Framework y clases como contenedoras de datos, permite un enlace bidireccional de datos de forma desconectada (igual que los DataSet). La eficacia e inteligencia con la que gestiona las lecturas y escrituras a la base de datos consiguen un rendimiento espectacular. A la vez, la potencia de las consultas integradas en el lenguaje (LINQ) permiten la extracción de datos de forma muy flexible y cómoda para el programador. Como limitación diremos que sólo permite la conexión con SQL Server, eso sí, en cualquiera de sus ediciones.
  • LINQ to Entities. Combina las consultas integradas en el lenguaje (LINQ) con Entity Framework. Básicamente es lo mismo que LINQ to SQL pero nos permite conectar con cualquier otro tipo de base de datos a través de OLEDB.
Desde mi experiencia, no es recomendable usar la misma técnica para todos los casos.

La más apropiada en cada caso dependerá de diversos factores. Entre ellos está la finalidad del enlace a realizar (mantenimiento de datos, ejecución de procesos, extracción de informes y gráficos, etc.), la velocidad de la conexión con la base de datos, etc...

La técnica que ofrece la mejor velocidad en lectura de datos es el uso de DataReaders. Leen secuencialmente los registros uno a uno y simplemente devuelven los datos leídos a medida que los vamos pidiendo. Por contra, requiere más líneas de código para procesarlos, dado que debemos indizar los campos devueltos (con un Enum, por ejemplo) para tener acceso a sus valores. También tenemos que encargarnos de la conversión del tipo de dato obtenido si es necesario. En resumen: alta velocidad de procesamiento pero más líneas de código a escribir. Sería la mejor elección para realizar lecturas de una gran cantidad de datos (decenas de miles de registros), con conexiones pobres en velocidad (bases de datos que están en Internet) o dentro de procesos muy largos donde se repiten amenudo las lecturas. Obviamente si necesitamos actualizar los datos leídos en la base de datos tendremos que usar objetos Command.

Los DataSets nos permiten un enlace completo (con inserciones, actualizaciones y eliminaciones). Se basan en un comando SELECT de SQL y el diseñador de Visual Studio nos genera automáticamente las instrucciones INSERT, UPDATE y DELETE. Cargan en memoria los datos leídos, permiten su modificación en memoria y la escritura de dichas modificaciones en el momento en que lo decidamos, manteniendo la integridad con los cambios de otros usuarios en la base de datos. Nos ahorran muchas líneas de código (que genera automáticamente el diseñador), y tienen un rendimiento muy aceptable. Es una elección óptima en el caso de mantenimientos de tablas de datos y casi la única si nuestro ensamblado sólo corre bajo la versión 2.0 de .Net Framework. En mi experiencia, cuando un DataSet contiene demasiadas tablas el diseñador resulta demasiado lento, lo que nos hace perder un poco la paciencia.

LINQ (to SQL y to Entities) para mí es la opción que sustituye a los DataSet (si podemos usar la versión 3.5 o superior de .Net Framework) por estas razones:
  • Ofrecen la misma funcionalidad (lectura, manipulación desconectada y escritura). Bueno, casi toda la funcionalidad. pues nativamente no integran el proveedor de errores (esos signos de admiración rojos que salen en los DataGrid cuando hay algún dato erróneo). No obstante, se puede implementar fácilmente mediante herencia.
  • Rendimiento similar o superior. En algunos casos muy concretos (queries con uno o dos campos en el resultado) ha resultado más rápido el DataSet, pero en general es al contrario. Además, LINQ nos permite compilar las consultas, lo que acelera su ejecución.
  • Baja dependencia del tipo de base de datos. No es necesario escribir ni una sóla consulta SQL contra la base de datos, pues LINQ actúa sobre tablas, no sobre consultas. Las consultas las realizamos después con LINQ sobre los datos leídos de las tablas. Esto tiene la ventaja de que no necesitamos ser expertos programadores de SQL Server u Oracle. A la vez descargamos de trabajo al servidor de la base de datos, pues no le encargamos complicadas consultas.
  • Facilísima implementación. Basta con arrastrar las tablas al diseñador del archivo .dbml o .edmx y ya está creada la clase con todos los campos lista para ser consultada. Después podemos crear asociaciones entre tablas y ya tenemos relaciones de uno a varios o de uno a uno disponibles en las propiedades de las clases.
  • Muy fácil de extender. Mediante Partial Class podemos dotar de nuestros propios métodos o propiedades a una tabla. A diferencia de los DataSet, cuando creamos una propiedad mediante código (que no se corresponde con un campo de la tabla), esta es enlazable directamente a un control de Windows Forms.
En general recomiendo usar esta técnica tanto para mantenimiento de datos como para informes y gráficos, con buenos resultados. No obstante, en casos donde el rendimiento es muy crítico, es mejor recurrir a DataReaders. Hay que tener en cuenta que las clases de LINQ to SQL son colecciones enlazables y, por lo tanto, requieren de unos recursos y necesitan una estructura interna que afecta a la velocidad de su llenado.

Conclusión:
  • DataReader: Usar sólo en situaciones de sólo lectura donde el rendimiento es crítico.
  • DataSet: Usar sólo si nuestra aplicación no corre con .Net Framework 3.5 o posterior o vamos a realizar un enlace con archivos XML.
  • LINQ: Usar en el resto de los casos.

No hay comentarios:

Publicar un comentario