LINQ to SQL (Parte 6 – Obtener datos con procedimientos almacenados)

En las últimas semanas he escrito una serie de post sobre LINQ to SQL. Es un ORM integrado en .NET 3.5, y nos permite modelar bases de datos relacionales con clases de .NET. Podemos usar expresiones LINQ para consultar a la base de datos, actualiazarla, insertar y borrar datos.

Aquí tenéis los enlaces a los otros post:

En estos posts vimos cómo usar expresiones LINQ para obtener programáticamente datos de la base de datos.

En el post de hoy veremos cómo podemos usar los procedimientos almacenados (SPROCs) y las funciones definidas por el usuario (UDFs) con nuestro modelo LINQ to SQL. El post de hoy veremos el caso de los SPROCs para consultar y obtener datos de la base de datos. En el siguiente post de esta serie veremos cómo actualizar/insertar/borrar datos con SPROCs.

¿SPROC o no SPROC? Esa es la cuestión

La pregunta sobre cuando usar el SQL dinámico generado por un ORM en lugar de procedimientos almacenados creando una capa de datos es causa de debates muy acalorados entre desarrolladores, arquitectos y DBAs. Mucha gente más lista que yo ha escrito sobre esto, así que no me decantaré ni por un lado ni por otro.

LINQ to SQL es muy flexible, y puede usare para crear un modelo de datos cuyos objetos sean independientes del esquema de la base de datos, y puede encapsular lógica de negocio y reglas de validación que funcionan tanto si se usa SQL generado dinámicamente o a través de SPROCs.

En el tercer post de esta serie, hablamos sobre cómo podemos escribir expresiones LINQ contra el modelo de LINQ to SQL como el siguiente código:

Cuando escribimos expresiones LINQ como esta, LINQ to SQL ejecutará el SQL dinámico necesario para obtener los objetos de Product que cumplan las restricciones.

Como aprenderemos en este post, también podemos mapear SPROCs en la base de datos con la clase DataContext generada por LINQ to SQL, que nos permitirá obtener los mismo objetos de Product llamando a un procedimiento almacenado:

Esta habilidad de poder usar tanto SQL dinámico como SPROCs  con una capa de datos limpia es muy útil y nos permite una gran flexibilidad en nuestros proyectos.

Pasos para mapear y llamar a SPROC con LINQ to SQL

En el segundo post de la serie vimos cómo usar el diseñador LINQ to SQL para crear el siguiente modelo de clases:

Fijaos en las dos partes del diseñador. La de la izquierda nos permite definir el modelo de datos que mapeara nuestra base de datos. El de la derecha nos permite mapear SPROCs (y UDFs) en nuestro objeto DataContext, que podemos usar en lugar del SQL dinámico para trabajar con los objetos de nuestro modelo de datos.

Cómo mapear un SPROC en un DataContext de LINQ to SQL

Para mapear SPROCs en la clase DataContext, vamos primero al explorador de servidores de VS 2008 y miramos a los SPROCs de nuestra base de datos:

Haciendo doble clic en cualquier SPROC se abrirá para edición y podremos ver el código. Por ejemplo, aquí tenéis el SPROC "CustOrderHist" de la base de datos Northwind:

Para mapearlo en nuestra clase DataContext, lo arrastarmos y soltamos desde el explorador de servidores al diseñador de LINQ to SQL. Automáticamente se creará un nuevo método en la clase DataContext:

Por defecto el nombre del nuevo método en la clase DataContext será el mismo que el del SPROC, y el tipo de datos devueltos se creará automáticamente con el siguiente patron: "[NombredelSPROC]Result". Por ejemplo: el SPROC de arriba devolverá una secuencia de objetos del tipo "CustOrderHistResult". Podemos cambiar el nombre del método seleccionándolo en el diseñador y cambiarlo en la ventana de propiedades.

Como llamar a un nuevo SPROC mapeado.

Una vez que hemos seguido los pasos para mapear el SPROC en la clase DataContext, es muy fácil de usar. Todo lo que tenemos que hacer es llamarlo para obtener los resultados fuertemente tipados:

En VB:

En C#:

Además de poder hacer un bucle sobre los resultados, también podemos enlazar los resultados con cualquier control para mostrarlos. Por ejemplo, el siguiente código enlaza los resultados del SPROC a un control <asp:gridview>

Con lo que mostramos la historia de productos de un cliente:

Mapeando los tipos resultado de los SPROC del modelo de datos

En el SPROC "CustOrderHist" devolvía una secuencia de objetos con dos columnas: el nombre del producto y el numero total de pedidos que el cliente ha hecho de ese producto. El diseñador LINQ to SQL definió la clase "CustOrderHistResult" para representar los resultados.

También podemos decidir mapear los resultados del SPROC a una clase de nuestro modelo de datos (por ejemplo: a una entidad Product o Order).

Por ejemplo, tenemos el SPROC "GetProductsByCategory" en nuestra base de datos que devuelve la siguiente información:

Como ántes podemos crear un método "GetProductsByCategory" en la clase DataContext que llama a este SPROC arrastrándolo al diseñador de LINQ to SQL. Más que simplemente arrastrar el SPROC al diseñador, lo arrastraremos encima de la clase "Product":

Con esto, el método "GetProductsByCategory" devolverá una secuencia de objetos "Product":

LINQ to SQL seguirá los cambios hechos a los objetos que se devuelvan como si fuesen objetos Products obtenidos a partir de expresiones LINQ. Cuando llamemos al método "SubmitChanges()" todos los cambios hechos a esos objetos se guardarán en la base de datos.

Por ejemplo, con el siguiente código obtenemos y cambiamos el precio de todos los productos de una categoría aumentándolo en un 90 %:

Para entender cómo funciona el método SubmitChanges() y el seguimiento que se hace de los cambios, y ver cómo podemos añadir lógica de negocio a nuestro modelo de datos leed el cuarto post de esta serie.

En el próximo post de esta serie veremos también cómo cambiar el SQL generado cuando insertamos/actualizamos/borramos datos con SPROCs personalizados. Lo bueno de todo esto es que el código anterior no habrá que cambiarlo si hemos configurado la clase DataContext para que use SPROCs para las actualizaciones -

Manejando resultados múltiples  desde SPROCs

Cuando un procedimiento almacenado puede devolver varios tipos de datos, el tipo de resultado del SPROC en la clase DataContext no puede ser fuertemente tipado. Por ejemplo, imaginemos el siguiente SPROC que puede devolver un producto o un pedido dependiendo del parámetro de entrada:

LINQ to SQL permite crear métodos auxiliares para devolver Product o Order añadiendo una clase parcial "NorthwindDataContext" al proyecto que defina un método (que en este caso llamaremos "VariablesShapeSample") que invoca al SPROC y devuelve un objeto IMultipleResult:

VB:

C#:

Una vez que añadimos este método al proyecto podemos llamarlo y convetir los resultados tanto a una secuencia de Product como de Order:

VB:

C#:

Soporte de funciones definidas por el usuario (UDFs)

Además de SPROCS, LINQ to SQL también soporta tanto funciones de usuario de valores y de tablas de valores (UDFs). Una vez que añadimos un método a la clase DataContext, podemos usar estas funciones en nuestras consultas LINQ.

Por ejemplo, veamos la función simple "MyUpperFunction":

Podemos arrastrar y soltar desde el explorador de servidores al diseñador de LINQ to SQL para añadirlo como un método a nuestro DataContext:

Luego podemos usar esta función UDF en expresiones LINQ cuando escribimos consultas contra nuestro modelo LINQ to SQL:

VB:

C#:

Si usamos el visualizador de debug de LINQ to SQL del que ya hablamos aquí, podemos ver cómo LINQ to SQL transforma la expresión anterior en una SQL que ejecutará el UDF en la base de datos en tiempo de ejecución:

 

Resumen

LINQ to SQL soporta poder usar procedimientos almacenados y UDFs contra la base de datos y los integra en nuestro modelo de datos. En este post hemos visto cómo podemos usar SPROCs para obtener datos y pasarlo entre nuestras clases del modelo. En el próximo post veremos cómo podemos usar SPROCS para sobreescribir la lógica de actualización/inserción/borrado cuando llamamos a SubmitChanges() en el DataContext para guardar los cambios.

Espero que sirva.

Scott.

Traducido por: Juan María Laó Ramos. Microsoft Student Partner.

toH tlhIngan Hol DajatlhlaH ‘e’ DaneH’a’?

9 pensamientos en “LINQ to SQL (Parte 6 – Obtener datos con procedimientos almacenados)

  1. Pingback: LINQ to SQL (Parte 9 - Uso de expresiones LINQ personalizadas con el control ) « Thinking in .NET

  2. Pingback: LINQ. que es y como usuarlo. « Alexander Jiménez

  3. Linda

    hola, tengo un problema porque requiero ejecutar un sp, que no esta ligado a una tabla definida sino variable, el código del sp es asi:

    var=’select ‘ +@nombrecampo+’ from ‘+ @nombretabla

    exec var

    el sp me regresa la consulta correcta pero no se como puedo implementarlo en c Sharp dado que siempre la relación del resultado se identifica con alguna tabla especifica.

    ¿Podrias ayudarme?
    Gracias

  4. Vio

    Hola Linda:

    Desde C# no puedes llamar “directamente” a un procedimiento almacenado en una base de datos, para ello debes usar las librerías de ADO.NET o para facilitarte el trabajo LINQ to SQL.
    El procedimiento almacenado debe existir en la base de datos que tengas montada. @nombretabla debe ser un parámetro que le pases al procedimiento.
    Si te refieres a escribir un procedimiento almacenado en c# pásate por aquí: http://msdn.microsoft.com/es-es/library/ms255336%28VS.80%29.aspx

    Espero que te sirva.

  5. ING. GARCIA

    Con esta nueva tecnologia linq to sql o linq to entities son necesarios los procedimientos almacenados, o cual es la mejor opcion hacer las consultas dinamicamente o usar procedimientos almacenados.

    Gracias.

  6. L.M.Santin

    Hola:

    ¿Cómo hacer en el caso que un SP tiene 3 SELECT?

    -El primer SELECT devuelve los detalles del cliente
    -El segundo SELECT devuelve las tiendas donde tiene contrato
    -El tercer SELECT devuelve las tiendas con las que NO tiene contrato.

    ¿Como quedaria definida la funcion en la partial class del Datacontext y la clase para el resultado?

    1. L.M.Santin

      La respuesta a mi pregunta la encontré en este articulo http://msdn.microsoft.com/en-us/library/bb399344.aspx

      Vale la pena aclarar que los tipos MultipleResultTypesSequentiallyResult1y MultipleResultTypesSequentiallyResult2 deben ser declarados en la clase parcial del Datacontext en el O/R designer, no en el codigo auto generado.
      Para declararlos de debe seguir las clases del codigo auto-generado como patron

  7. Cristina

    hola, tengo hecho un crystalreportviewer, conectandome a la bd con linq to sql. ten el data set le tengo creada una select y mostrando los campos filtrados. bien ahora quiero poder ordenarlos. cuando le pongo a esa consulta el order by, y le doy a generar consulta me la crea bien, lo que creo que el problema lo tiene el crystalreportviewer, porque ahi se muestra siempre de la misma forma, y no se ordena por la columna que yo le muestro

Los comentarios están cerrados.