O dicho de otra forma: Si usamos LINQ, ¿podemos olvidarnos de nuestros componentes propios o genéricos de acceso a datos? (por ej. Data Access Block de Enterprise Library). Para dar una respuesta simple: NO, de ninguna manera.
Al menos si consideramos cualquier aplicacion basada en SQL Server que no sea trivial (en cuanto a su modelo de datos o la concurrencia de usuarios), no hay mucha duda de que los procedimientos almacenados siguen teniendo un rol clave en el acceso a los datos.
Su funcionalidad ahora puede ser complementada con consultas o actualizaciones directas via LINQ, en una mezcla cuya proporcion dependerá del contexto de la aplicación: desde "sólo procedimientos almacenados" en algunos entornos corporativos, hasta escenarios con una buena proporción de consultas LINQ en otros entornos. En cualquier caso, las consultas complejas y actualizaciones críticas requerirán ser implementadas como procedimientos almacenados.
Una vez establecido esto, volvemos a la pregunta inicial: ¿es necesario "duplicar" el código de acceso a datos, teniendo en cuenta que LINQ para SQL ya implementa la conexión con la base de datos y tiene un mecanismo para la invocación de procedimientos almacenados?
Se me ocurren varias razones que justifican mantener un mecanismo separado para las invocaciones a procedimientos almacenados:
- Posibilidad de control: típicamente hay una serie de tareas y controles que se aplican antes y despues de las invocaciones, en el código genérico de invocacion de SP: revisar y completar parámetros (ej. Id del usuario autenticado), manejar excepciones, ajustar timeout de la conexion, etc.
- Capacidad de retornar distintos tipos de resultado: ej. valores escalares, Data Readers, XML Readers
- Posibilidad de retornar datasets en forma sencilla. Si, por supuesto. ¿o acaso la aparición de LINQ significa la extinción de los datasets? En muchas situaciones, un dataset sigue siendo una forma muy simple y eficiente de trasladar datos tabulares entre capas de la aplicación.
- Capacidad de retornar tambien colecciones de objetos (o instancias simples) como resultado de la invocación a un procedimiento almacenado. Esto puede realizarse mediante código propio (examinando atributos de las entidades o utilizando Reflection sobre los miembros) o utilizando el método Translate del mismo DataContext de LINQ to SQL. Esto último requiere atributos LINQ en la definicion de las clases, pero estos atributos son creados automáticamente por nuestro generador de código asociado a un modelo DBML que se edita con el mismo diseñador O/R de Visual Studio 2008.
Como criterio de aplicación, nosotros en general utilizamos la siguiente regla:
- Todas las invocaciones a procedimientos almacenados las realizamos a traves de la DAL (Data Access Layer) propia, aún las que retornan colecciones o instancias de entidades.
- Para las consultas y actualizaciones de LINQ sobre SQL utilizamos el mecanismo de acceso a datos incluido en el Data Context.
Esta combinación le da, a nuestro "framework" de construcción de aplicaciones, la máxima flexibilidad para adaptarse a distintos escenarios y aún a distintos casos de uso dentro de la misma empresa (ej. un sistema de reserva de salas no requiere la misma complejidad de solución que un sistema de gestión de inventarios).