usando linq to sql

114
Usando LINQ to SQL (1ª Parte) En los últimos meses he escrito una serie de post que cubrían algunas de las característcias que van a venir con Visual Studio y .NET Framework “Orcas”. Aquí tenéis los enlaces: Propiedades automáticas, inicializadores de objectos e inicializadores de colleciones. Métodos de extensión. Expresiones Lambda . Sintaxis de consultas. Tipos Anónimos Las características anteriores hacen que la consulta de datos sea un concepto de primera clase. Conocemos a este modelo de programación como “LINQ” – que viene de .NET Language Integrated Query. Los desarrolladores pueden usar LINQ con cualquier fuente de datos. Pueden expresar consultas eficientemente en los lenguajes de programación que eligan, opcionalmente transformar/incrustar los resultados de las consultas en el formato que quieran, y entonces manipular fácilmente los resultados. Los lenguajes habilitados para LINQ pueden aportar seguridad de tipos y chequeo en tiempo de compilación el las expresiones de consulta, y desarrollar herramientas que aporten intelisense, debugging, y un gran soporte para refactoring cuando escriban código de LINQ. LINQ soporta un modelo de extensibilidad muy rico que facilita la creación de operadores eficientes para fuentes de datos. La versión “Orcas” del .NET Framework biene con librerías que habilitan LINQ sobre objetos, XML y bases de datos. ¿Qué es LINQ to SQL? LINQ to SQL es una implementación de O/RM(object relational mapping, mapeador de objetos relacionales) que viene con la versión “Orcas” del .NET Framework, y nos permite modelar bases de datos relacionales con clases de .NET. Podemos consultar bases de datos con LINQ, así como actualizar/añadir/borrar datos de ellas. Modelando bases de datos con LINQ to SQL: Visual Studio “Orcas” viene con un diseñador de LINQ to SQL que nos aporta una forma fácil de modelar y visualizar una base de datos como un modelo de objeto de LINQ to SQL. El próximo post cubrirá en más profundidad cómo usar este diseñador (podéis ver éste video que hice en Enero para verme construir un modelo LINQ to SQL). Usando ese diseñador LINQ to SQL puedo crear fácilmente una representación de la base de datos “Northwind”:

Upload: vladimir-vlack

Post on 26-Jun-2015

5.929 views

Category:

Documents


1 download

TRANSCRIPT

Page 1: Usando Linq to SQL

Usando LINQ to SQL (1ª   Parte)

En los últimos meses he escrito una serie de post que cubrían algunas de las característcias que van a venir con Visual

Studio y .NET Framework “Orcas”. Aquí tenéis los enlaces:

Propiedades automáticas, inicializadores de objectos e inicializadores de colleciones.

Métodos de extensión.

Expresiones Lambda .

Sintaxis de consultas.

Tipos Anónimos

Las características anteriores hacen que la consulta de datos sea un concepto de primera clase. Conocemos a este

modelo de programación como “LINQ” – que viene de .NET Language Integrated Query.

Los desarrolladores pueden usar LINQ con cualquier fuente de datos. Pueden expresar consultas eficientemente

en los lenguajes de programación que eligan, opcionalmente transformar/incrustar los resultados de las consultas

en el formato que quieran, y entonces manipular fácilmente los resultados. Los lenguajes habilitados para LINQ

pueden aportar seguridad de tipos y chequeo en tiempo de compilación el las expresiones de consulta, y

desarrollar herramientas que aporten intelisense, debugging, y un gran soporte para refactoring cuando escriban

código de LINQ.

LINQ soporta un modelo de extensibilidad muy rico que facilita la creación de operadores eficientes para fuentes de

datos. La versión “Orcas” del .NET Framework biene con librerías que habilitan LINQ sobre objetos, XML y bases de

datos.

¿Qué es LINQ to SQL?

LINQ to SQL es una implementación de  O/RM(object relational mapping, mapeador de objetos relacionales)  que viene

con la versión “Orcas” del .NET Framework, y nos permite modelar bases de datos relacionales con clases de .NET.

Podemos consultar bases de datos con LINQ, así como actualizar/añadir/borrar datos de ellas.

Modelando bases de datos con LINQ to SQL:

Visual Studio “Orcas” viene con un diseñador de LINQ to SQL que nos aporta una forma fácil de modelar y visualizar

una base de datos como un modelo de objeto de LINQ to SQL. El próximo post cubrirá en más profundidad cómo usar

este diseñador (podéis ver éste video   que hice en Enero para verme construir un modelo LINQ to SQL).

Usando ese diseñador LINQ to SQL puedo crear fácilmente una representación de la base de datos “Northwind”:

Page 2: Usando Linq to SQL

El diseño de arriba define cuatro clases: Product, Category, Order y OrderDetail. Las propiedades de cada clase

mapean las columnas de cada table en la base de datos. Cada instancia de esa clase representa una fila en las tablas.

Las flechas entre las cuatro clases de arriba representan las asociaciones/relaciones entre las diferentes entidades.

Son típicamente modeladas como relaciones primary-key/foreign-key en la base de datos. La dirección de las flechas

en el diseñador indican si la relación es uno-a-uno o uno-a-varios. Se añadiran propiedades fuertemente tipadas a las

entidades basándose en esto. Por ejemplo, la clase Category de arriba tiene una relación de uno-a-varios con la clase

Product. Esto implica que tendrá una propiedad “Categories” que es una colección de objetos Product con esa

categoría. La clase Product entonces tiene una propiedad “Category” que apunta a una instancia de la clase Category

representando la categoría a la que pertenece el producto.

El panel de la derecha del diseñador LINQ to SQL contiene una lista de procedimientos almacenados que interactúan

con nuestro modelo de base de datos. En el ejemplo de arriba hemos añadido un SPROC (Procedimiento almacenado)

“GetProductsByCategory”. Como entrada recibe un categoryID, y devuelve una secuencia de Product como resultado.

Veremos cómo llamar a este procedimiento almacenado en un ejemplo.

Page 3: Usando Linq to SQL

Entendiendo la clase DataContext

Cuando pulsáis el boton “save” del diseñador de LINQ to SQL, Visual Studio generará clases .NET para representar las

entidades y las relaciones de la base de datos que hemos modelado. Por cada archivo añadido a nuestra solución por

el diseñador LINQ to SQL también se generará una clase DataContext. Esta clase es a traves de la cual realizaremos

las consultas a las entidades de nuestra base de datos. Esta clase tendrá propiedades que representarán a cada tabla

que hemos modelado, así como métodos para cada procedimiento almacenado que añadamos.

Por ejemplo, aquí tenéis la clase NorthwindDataContext:

Ejemplos de LINQ to SQL

Una vez que hemos modelado nuestra base de datos con el diseñador de LINQ to SQL, podemos escribir código

fácilmente para trabajar con él. Aquí tenéis unos cuantos ejemplos que muestran tareas comunes con datos:

1) Consultando Products de la base de datos

El siguiente código usa una consulta LINQ para obtener una secuencia IEnumerable de objetos Product. Fijáos que este

código está consultando a traves de la relación Product/Category para obtener aquellos productos de la categoría

“Beverages”.

Page 4: Usando Linq to SQL

 C#:

VB:

2) Actualizando un producto en la base de datos.

El código siguiente muestra cómo obtener un producto de la base de datos, actualizar su precio, y guardar los cambios

en la base de datos:

C#:

VB:

Nota: VB en “Orcas” Beta1 no soporta Lambdas aún. Pero en la Beta2 sí -de forma que el código anterior se podrá

escribir de una forma más concisa.

3) Añadir una nueva categoría y dos nuevos productos en la base de datos.

Page 5: Usando Linq to SQL

El siguiente código muestra cómo crear una nueva categoría, y entonces crear dos nuevos productos y asociarlos a la

nueva categoría. Los tres son después guardados en la base de datos.

Fijaos como no necesitamos administrar manualmente las relaciones primarykey/foreignkey. Sólo tenemos que añadir

los objetos Product en la colección “Products” de la categoría, y luego añadir el nuevo objeto Category en la colección

de “Categories” del DataContext, LINQ to SQL sabrá automáticamente crear las PF/FK necesarias:

C#:

4)Borar productos de la base de datos.

El código siguiente muestra cómo borrar todos los productos Toy de la base de datos:

C#:

VB:

Page 6: Usando Linq to SQL

5) Llamar a un procedimiento almacenado.

El código siguiente muestra cómo obtener entidades de la tabla Product sin usar una consulta LINQ, sino llamando al

procedimiento almacenado “GetProductsByCategory” que añadimos a nuestro modelo de datos. Fijáos que cuando

obtenemos los resultados de la tabla Product, podemos actualizar/borrarlos y llamar a db.SubmitChanges() para hacer

las modificaciones en la base de datos.

C#:

VB:

Page 7: Usando Linq to SQL

6) Obtener productos con paginado del lado del servidor

El código siguiente muestra cómo implementar un paginado eficiente en el lado servidor como parte de una consulta

LINQ. Usando los operadores Skip() y Take(), sólo devoleremos 10 filas de la base de datos – a partir de la fila 200.

C#:

VB:

Resúmen:

LINQ to SQL nos permite modelar la capa de datos de nuestras aplicaciones de una forma simple y limpia. Una vez que

hayamos definido nuestro modelo de datos, podemos realizar consultas, inserciones, actualizaciones y borrados sobre

ella de forma fácil y eficiente.

Page 8: Usando Linq to SQL

LINQ to SQL (2ª Parte – Definiendo nuestras clases del modelo de   datos)

Publicado en .NET, ASP .NET, LINQ, LINQ to SQL, Visual Studio a 12:06 am por Juanma

En la primera parte   de la serie de post sobre LINQ to SQL hablé sobre “¿qué es LINQ to SQL?” y vimos por encima

algunos escenarios que permite.

En aquél post pusimos unos cuantos ejemplos de código donde demostrábamos cómo mejorar la parte de datos

usando LINQ to SQL:

Cómo consultar una base de datos.

Cómo actualizar filas en una base de datos

Cómo añadir y relacionar varias filas en una base de datos.

Cómo eliminar filas de la base de datos.

Cómo llamar a procedimientos almacenados.

Cómo obtener datos con paginación en el servidor.

 Mejoramos todos estos escenarios usando un modelo de clases de LINQ to SQL como éste:

Page 9: Usando Linq to SQL

En este segundo post de la serie vamos a ver en más detalle cómo crear el modelo anterior con LINQ to SQL.

LINQ to SQL, el diseñador de LINQ to SQL, y todas las características que estamos viendo saldrán con la versión

de .NET 3.5 y en la release de Visual Studio “Orcas”.

Podéis seguir todos los pasos siguientes descargándo tanto Visual Studio “Orcas” Beta 1 o Visual Web Developer

Express “Orcas” Beta 1. Podéis instalar las dos y usarlas sin ningún problema con Visual Studio 2005. 

Crear un nuevo modelo de datos LINQ to SQL

Podemos añadir un modelo de datos de LINQ to SQL a un projecto ASP.NET, Class Library o Windows, con la nueva

opción “Add New Item” seleccionando “LINQ to SQL”:

Seleccionando “LINQ to SQL” lanzará el diseñador de LINQ to SQL, y nos permitirá modelar las clases que representen

una base de datos relacional. También creará una clas fuertemente tipada “DataContext” que tendrá las propiedades

que representarán cualquier tabla que modelemos de la base de datos, así como métodos para cada procedimiento

almacenado que modelemos. Como describimos en la primera parte   de esta serie de post, la clase DataContext es el

conducto principal que usaremos tanto para consultar la base de datos como para guardar los cambios que hagamos.

Aquí tenéis una captura de pantalla de un diseño LINQ to SQL ORM vacío, es lo que veréis despues de crear un nuevo

modelo de datos LINQ to SQL:

Page 10: Usando Linq to SQL

Clases Entidad (Entity)

LINQ to SQL nos permite modelar clases que mapeen una base de datos. Estas clases son típicamente conocidas como

“Clases Entidad” (en ingles “Entity Classes”) y a las instancias se las conoce como “Entidades” (en ingles “Entities”).

Las clases entidad mapean a tablas de una base de datos. Las propiedades de una clase entidad normalmente

mapean las columnas de la tabla. Cada instancia de una clase entidad representa a una fila de una tabla de la base de

datos.

Las clases entidad definidas por LINQ to SQL no tienen que derivar de una clase base específica, lo que significa que

pueden heredar de cualquier objeto que queramos. Todas las clases creadas por el diseñador de LINQ to SQL se

definen como “clases parciales” – con lo que podemos, opcionalmente, añadir propiedades adicionales, métodos y

eventos.

A diferencia de la característica de DataSet/TableAdapter que aporta VS 2005, cuando usamos el diseñador de LINQ to

SQL no tenemos que especificar qué consultas SQL se tiene que usar cuando creamos el modelo de datos y la capa de

acceso.

En lugar de eso, nos centramos en definir las clases entidad, cómo se mapean con la base de datos, y las relaciones

entre ellas. La implementación del ORM de LINQ to SQL se encargará de generar la lógica de ejecución SQL por

nosotros en tiempo de ejecución para que podamos interactuar y usar las entitades de datos. Podemos usar sintaxis

de consultas LINQ para indicar cómo consultar nuestro modelo de datos de forma fuertemente tipada.

Crear clases entidad de la base de datos.

Si ya tenemos un esquema de base de datos definido, podemos usarlo para crear clases entidad LINQ to SQL.

Page 11: Usando Linq to SQL

La forma más sencilla de conseguirlo es abrir la base de datos desde el “Server Explorer” de Visual Studio, seleccionar

las tablas y vistas (Views) que queramos modelar, y arrastrarlas al diseñador LINQ to SQL:

Cuando añadimos estas dos tablas (Categories y Products) y una vista (Invoices) de la base de datos “Northwind” al

diseñador de LINQ to SQL, tendremos las siguientes clases entidad creadas a partir del esquema de la base de datos:

Page 12: Usando Linq to SQL

Usando estas clases, podemos ejecutar todos los ejemplos de código (excepto el de procedimientos almacenados) que

vimos en la primera parte   de esta serie sobre LINQ to SQL. No tenemos que añadir ningún código adicional o

configuración para habilitar los escenarios de consulta, inserción, actualización, borrado, y paginación en el servidor.

Nombrado y pluralización

Una de las cosas de las que os daréis cuenta usanto el diseñador de LINQ to SQL es que automáticamente “pluraliza”

los nombres de las tablas y columnas cuando crea las clases entidad basádas en el esquema de la base de datos. Por

ejemplo: la tabla “Products” del ejemplo se resuelve en una clase “Product”, y la tabla “Categories” se resuelve en la

clase “Category”. Este nombrado de clases hace que vuestro modelo sea más consistente con las convenciones de

nomenclatura de .NET, y encuentro bastante útil que el diseñador haga esto por mi (especialmente cuando añadimos

muchas tablas a nuestro modelo).

Si no os gusta el nombre de una clase o propiedad que el diseñador ha generado, siempre podréis cambiarlo por el

que queráis. Podéis hacerlo editanto el nombre de la entidad/propiedad en el mismo diseñador o cambiarlo en la rejilla

de propiedades:

Page 13: Usando Linq to SQL

Esta habilidad de nombrado de entidades/propiedades/asociaciones es muy útil en un gran número de casos. En

particular:

1) Cuando cambie el nombre de una tabla/columna de vuestra base de datos. Como vuestras entidades tendrán

nombres diferentes, podéis decidir actualizar las reglas de mapeado  y no el código de vuestra aplicación o las

consultas para usar esas nuevas tablas/columnas.

2) Cuando en el esquema de la base de datos tengais nombres que no son “limpios”. Por ejemplo, en lugar de usar

“au_lname” y “au_fname” para los nombres de las propiedades en una clase entidad, podéis usar los nombres de

“LastName” y “FirstName” en vuestras clases entidad y programar con esos nombres, en vez de cambiarlo en la base

de datos.

Relaciones

Cuando arrastremos objetos del “server explorer” al diseñador “LINQ to SQL”, Visual Studio comprobará las relaciones

de clave primaria y ajenas de los objetos, y basándose en ellas creará relaciones por defecto entre las diferentes

clases entidad que genere. Por ejemplo, cuando añadimos las tablas Products y Categories de la base de datos

NorthWind al diseñador LINQ to SQL podemos ver que se ha deducido una relación de uno a n entre ellas (esto se

indica con la felcha del navegador):

Esta relación hará que la clase entidad Product tenga una propiedad llamada “Category” que los desarrolladores

usarán para acceder a la entidad Category para un Product dado. También hará que la clase Category tenga una

colección de “Products” que permitirá a los desarrolladores obtener todos los productos de una Category.

Page 14: Usando Linq to SQL

Si no nos gusta cómo el diseñador a nombrado a la relación, siempre podrémos cambiarlo. Sólo hay que hacer clic en

la felcha en el diseñador, ver las propiedades y cambiar el nombre.

Retrasar la carga

LINQ to SQL permite a los desarrolladores especificar si las propiedades de las entidades deben precargarse o

retrasarse hasta el primer acceso. Podemos personalizar las reglas de precarga/retraso para las propiedades de las

entidades seleccionando cualquier propiedad o asociación en el diseñador, y en las propiedades poner la propiedad

“Delay Loaded” a true o false.

Por poner un ejemplo, imaginemos la clase entidad “Category” del modelo anterior. La tabla “Categories” de la base

de datos “NorthWind” tiene una columna “Picture” que contiene una imagen (potencialmente grande) para cada

categoría, y sólo queremos esa imagen cuando vaya a usarla (y no cuando esté haciendo una consulta para obtener

los nombres de las categorías en una lista).

Podríamos configurar la propiedad Picture para que se retrase su carga seleccionandola en el diseñador de LINQ to

SQL y en las propiedades poner “Delay Loaded” a true:

Page 15: Usando Linq to SQL

Nota: Además de configurar el significado de la precarga/retraso de las entidades, podemos sobreescribirlo vía código

cuando hagamos consultas LINQ en las clases entidad (lo veremos en el siguiente post de esta serie).

Usando procedimientos almacenados.

LINQ to SQL nos permite modelar procedimientos almacenados como métodos de nuestra clase DataContext. Por

ejemplo, supongamos que hemos definido un procedimiento almacenado simple para obtener la información de un

producto de un categoryID:

Podemos usar el server explorer de Visual Studio y arrastrar este procedimiento almacenado al diseñador de LINQ to

SQL para obtener un método fuertemente tipado que invocará a este procedimiento almacenado. Si lo arrastramos

encima de la entidad “Product” en el diseñador, el diseñador declarará que el procedimiento almacenado devuelve un

IEnumerable<Product>:

Page 16: Usando Linq to SQL

Podemos usar tanto una consulta SQL (que generará una consulta SQL adhoc) o invocar el procedimiento almacenado

añadido para obtener las entidades product de la base de datos:

Page 17: Usando Linq to SQL

Usar procedimientos almacenados para actualizar/borrar/insertar datos.

Por defecto LINQ to SQL creará automáticamente expresiones SQL apropiadas para cuando tengamos que

insertar/actualizar/borrar entidades. Por ejemplo, si escribimos el siguiente código LINQ to SQL para actualizar algunos

valores en una instancia de la entidad “Product”:

LINQ to SQL creará y ejecutará una sentencia “UPDATE” apropiada para cuando aceptemos los cambios (Veremos esto

en más profundidad en otros post).

Podemos definir procedimientos almacenados personalizados para INSERT, UPDATE, DELETE. Para configurar esto,

hacemos clic en una entidad del diseñador LINQ to SQL y en las propiedades de Delete/Insert/Update, en el botón “…”,

y ponemos un procedimiento almacenado que ya hayamos definido.

Lo curioso es que el cambio de estas propiedades se está realizando en la capa de mapeo de LINQ to SQL – lo que

implica que la actualización del código que vimos ántes sigue funcionando sin tener que hacer ninguna modificación.

Con esto libramos a los desarrolladores de que si cambiamos el modelo de datos LINQ to SQL, no tienen que tocar

ningún código para que sigua funcionando si deciden poner un procedimiento almacenado personalizado.

Page 18: Usando Linq to SQL

Resumen

LINQ to SQL provee una forma limpia de modelar las capas de datos de nuestras aplicaciones. Una vez que tengamos

nuestro modelado de datos, podemos realizar de forma eficiente consultas, inserciones, actualizaciones, y borrados

sobre él.

Con el diseñador de LINQ to SQL que viene en Visual Studio y en Visual Web Developer Express podemos crear y

administrar nuestros modelso de datos para LINQ to SQL extremadamente rápido. El diseñador LINQ to SQL también

permite una gran flexibilidad que nos permite personalizar el comportamiento por defecto y sobreescribir/extender el

sistema para que se adapte a nuestras necesidades.

En próximos post usaremos este modelo que hemos creado para ver en más detalle los procesos de consulta,

inserciones, actualizaciones y borrados. En estos post también veremos cómo añadir validaciones negocio/datos

personalizadas a las entidades que hemos diseñado.

Mike Taulty tiene una gran cantidad de videos sobre LINQ to SQL aquí, os recomiendo que los veáis. Así tenéis una

forma de aprender viendo cómo se usa LINQ to SQL.

LINQ to SQL (3ª Parte – Consultando la base de   datos)

Publicado en .NET, ASP .NET, LINQ, LINQ to SQL, Scott Guthrië a 1:04 pm por Juanma

El mes pasado empezé una serie de post sobre LINQ to SQL. LINQ to SQL es un framework O/RM (Object relational

mapping) que viene como parte del .NET Framework 3.5, que nos permite modelar de forma sencilla bases de datos

relacionales con clases de .NET. Podemos usar, por tanto, expresiones LINQ tanto para consultar a la base de datos

como para actualizar/inertar/borrar datos.

Aquí tenéis los enlaces a los primero dos post de esta serie:

Usando LINQ to SQL (1ª   Parte)

LINQ to SQL (2ª Parte – Definiendo nuestras clases del modelo de   datos)

En el post de hoy vamos a ver en más detalle cómo usar el modelo de datos que creamos en la segunda parte, y

veremos cómo usarlo para consultar datos en un proyecto ASP.NET.

Modelo de la base de datos Northwind con LINQ to SQL

En el segundo post de la serie vimos cómo crear un modelo de clases LINQ to SQL usando el diseñador de LINQ to SQL

que viene con VS 2008. Aquí tenéis el modelo que creamos a partir de la base de datos de ejemplo Northwind:

Page 19: Usando Linq to SQL

Obteniendo productos.

Una vez que tenemos definido nuestras clases del modelo de datos, podemos consultar y obtener fácilmente datos de

nuestra base de datos. LINQ to SQL nos permite esto usando la sintáxis de consultas de LINQ sobre la clase

NorthwindDataContext que creamos con el diseñador LINQ to SQL.

Por ejemplo, para obtener e iterar sobre una secuencia de objetos Product podemos escribir el siguiente código:

Page 20: Usando Linq to SQL

En esta consulta hemos usado la sentencia “where” en nuestra consulta LINQ para devolver aquellos productos de una

categoría. Estamos usando el campo/propiedad CategoryID del producto para hacer el filtro.

Una de las cosas que nos aporta LINQ to SQL es que nos da una total flexibilidad en cómo consultar nuestros datos, y

podemos aprovecharnos de las asociaciones que hicimos cuando modelamos las clases de LINQ to SQL para hacer

consultas más naturales y ricas sobre la base de datos. Por ejemplo, podemos modificar el filtro de la consulta por el

CategoryName en lugar de por el CategoryID con la siguiente consulta LINQ:

Fijáos en cómo estamos usando la propiedad “Category” de cada objeto Product para filtrarlos por CategoryName.

Esta propiedad fue creada automáticamente por LINQ to SQL ya que modelamos las clases Category y Product con

una relación “varios a uno” en la base de datos.

Por poner otro ejemplo del uso de las relaciones de nuestro modelo, podríamos escribir la siguiente consulta LINQ para

obtener aquellos productos que tengan más de cinco órdenes para ellos:

Page 21: Usando Linq to SQL

Fijáos cómo usamos la colección “OrderDetails” que LINQ to SQL creó en cada clase Product (debido a la relación 1 a

varios que modelamos en el diseñador LINQ to SQL).

Visualizando consultas LINQ to SQL en el debugger

Los ORM como LINQ to SQL administran automáticamente la creación y la ejecución del código SQL cuando realizamos

consultas o actualizaciones sobre su modelo de objetos.

Una de los mayores preocupaciones que tienen los desarrolladores sobre los ORMs es “¿pero qué código SQL se está

ejecutando?” Una de las cosas que hace LINQ to SQL es poder ver exáctamente qué código SQL se está ejecutando

cuando ejecutamos nuestra aplicación con el debugger.

Con la beta 2 de VS 2008 podemos usar el nuevo plug-in de visualización LINQ to SQL para ver (y testear) cualquier

consulta LINQ to SQL. Simplemente añadimos un breakpoint y pasamos el ratón por encima y hacemos clic en la lupa

para visualizar esa consulta:

ESto nos mostrará un cuadro de diálogo que nos dirá exactamente la SQL que LINQ to SQL usará cuando se ejecute la

consulta para obtener los objetos Product:

Si pulsamos el botón “Execute” de este diálogo nos permitirá evaluar el SQL dentro del debugger y nos mostrará los

resultados de la base de datos:

Page 22: Usando Linq to SQL

Obviamente esto hace realmente fácil ver qué lógica de consultas SQL está realizando LINQ to SQL. Fijáos que

podemos sobreescribir la SQL que LINQ to SQL ejecutará si queremos cambiarlo - sin embargo, en el 98% de los casos

creo que os dareis cuenta de que el código SQL que LINQ to SQL ejecuta es realmente bueno.

Enlazando consultas LINQ to SQL a controles ASP.NET

Los resultados de las consultas LINQ implementa la interfaz IEnumerable – la cual es una interfaz que los controles de

servidor de ASP.NET soportan para enlazar datos. Lo que implica que podemos enlazar los resultados de cualquier

consulta LINQ, LINQ to SQL, o LINQ to XML a cualquier control ASP.NET.

Por ejemplo, podemos declarar un control <asp:gridview> en una página .aspx de la siguiente forma:

Luego, podemos enlazar los resultados de la consulta LINQ to SQL que escribimos antes:

Page 23: Usando Linq to SQL

Esto generará una página como la siguiente:

Restringiendo los resultados de la consulta.

Hasta ahora, cuando evaluamos una consulta de productos, estamos obteniendo por defecto todas las columnas de

datos necesarias para cubrir la entidad de Product.

Por ejemplo, esta consulta para obtener productos:

Page 24: Usando Linq to SQL

El resultado de esta consulta es:

Normalmente sólo queremos un subconjunto de los datos de cada producto. Podemos usar la nueva característica que

LINQ y los compiladores de C# y VB tienen para indicar que sólo queremos un subconjunto de los datos, modificando

la consulta LINQ to SQL de la siguiente forma:

Con esto obtendremos un subconjunto de los datos que se obtienen de la base de datos (como vemos con el visor del

debugger):

Page 25: Usando Linq to SQL

Lo realmente útil de LINQ to SQL es que podemos aprovecharnos de las asociaciones entre clases de nuestro modelo

de datos cuando restringimos los datos. Esto nos permite expresar consultas útiles y muy eficientes. Por ejemplo, la

siguiente consulta obtiene los ID y los nombres de la entidad Product, el número total de pedidos que hemos hecho de

productos, y los suma al total de pedidos de Productos:

La expresión a la derecha de la propiedad “Revenue” es un ejemplo del uso delmétodo de extensión “Sum” de LINQ.

Toma una expresión Lambda   que devuelve el valor de cada pedido de producto como argumento.

LINQ to SQL es listo y es capaz de transformar la expresión LINQ anterior al siguiente SQL cuando es evaluado (con el

visor del debugger):

Page 26: Usando Linq to SQL

La sentencia SQL anterior hace que los valores NumOrders y Revenue se calculen dentro del servidor SQL, y devuelve

los siguientes valores de la base de datos (realmente rápido):

Podemos enlazar el resultado anterior a nuestro gridview:

Page 27: Usando Linq to SQL

BTW – en caso de que os lo preguntéis, tenemos intellisense en VS 2008 cuando escribimos estos tipos de

restricciones en las consultas LINQ:

Page 28: Usando Linq to SQL

En este ejemplo estamos declarando un tipo anónimo   que usa la inicialización de objetos   para amoldar y definir la

estructura del resultado. Y seguimos teniendo intellisense en VS 2008, chequeo de compilación y soporte para

refactoring con estos tipos anonimos:

Paginando los resultados de la consulta.

Page 29: Usando Linq to SQL

Una de las necesidades más comunes en entornos web es la posibilidad de hacer eficientemente la paginanción en las

interfaces de usuario. LINQ tiene dos métodos de extensión que permite hacer esto de forma fácil y eficiente – los

métodos Skip() y Take().

Podemos usar los métodos Skip() y Take() para indicar que sólo queremos devolver 10 objetos producto – desde la fila

que le pasemos como argumento:

Fijáos que no añadimos ni Skipt() ni Take() en la primera consulta – sino que lo hacemos después de la consulta

(cuando lo enlazamos a la fuente de datos del GridView). Muchos me preguntan “¿pero esto no significa que primero

obtiene todos los datos de la base de datos y luego hace la paginación (esto es malo)?” No. La cuestión es que LINQ

usa un modelo de ejecución en diferido, es decir, la consulta no se ejecuta hasta que se itera sobre los resultados.

Uno de los beneficios de este modelo de ejecución en diferido es que nos permite crear consultas en varias líneas de

código (lo que mejora la claridad). También nos permite crear las consultas después de otras – lo que nos permite

composiciones más flexibles y reutilización.

Una vez que tenemos el método BindProduct(), podemos escribir el siguiente código en nuestra página para obtener el

índice de inicio de la consulta y hacer que los productos sean paginados y mostrados en el gridview:

Esto nos dará una página de productos, filtrada para mostrar aquellos productos que tengan más de cinco pedidos,

mostrando datos calculados dinámicamente, y que son paginables a partir de una cadena de consulta:

Page 30: Usando Linq to SQL

Nota: Cuando trabajamos contra SQL 2005, LINQ to SQL usará la función SQL ROW_NUMBER() para crear toda la lógica

de paginación en la base de datos. Esto nos asegura que sólo devolverá las 10 filas de datos que queremos  mostrar

en la página:

Esto hace realmente fácil y eficiente navegar por grandes cantidades de datos.

Page 31: Usando Linq to SQL

Resumen

Hemos visto por encima alguna de las cosas que LINQ to SQL nos ofrece. Para aprender más sobre expresiones LINQ y

las nuevas características de consultas que traen los compiladores de C# y VB con VS 2008, leed estos post:

Nuevas características de la nueva versión de C#   Orcas

Métodos de   extensión.

Expresiones   Lambda

Sintaxis de   consultas

Tipos   anónimos

LINQ to SQL (4ª Parte) – Actualizando la base de   datos

Publicado en .NET, ASP .NET, LINQ, LINQ to SQL, Scott Guthrië, SQL, Visual Studio a 5:02 pm por Juanma

En las últimas semanas he escrito una serie de post sobre LINQ to SQL. LINQ to SQL es un O/RM(object relational

mapper) integrado en la versión 3.5 del framework de .NET, y nos permite modelar fácilmente bases de datos

relacionales en clases de .NET. Podemos usar expresiones LINQ tanto para consultar la base de datos como para

actualizar, insertar y borrar datos.

Aquí tenéis los links a los tres primeros post:

Parte 1: Introducción a LINQ to SQL

Parte 2: Definiendo el modelo de datos.

Parte 3: Consultando la base de datos

En el post de hoy veremos cómo usar el modelo de datos que hemos creado, y usarlo para actualizar, insertar y borrar

datos. También veremos cómo integrar reglas de negocio y crear lógica de validación personalizada con nuetro

modelo de datos.

Modelado de la base de datos NorthWind con LINQ to SQL

En la segundo post de esta serie, vimos cómo crear el modelo de clases con el diseñador de LINQ to SQL que trae VS

2008. Aquí tenéis el modelo que creamos a partir de la base de datos de ejemplo Northwind que usaremos en este

post:

Page 32: Usando Linq to SQL

Cuando definimos el modelo definimos cinco clases: Product, Category, Customer, Order y OrderDetail. Las

propiedades de cada clase mapean las diferentes columnas de las tablas correspondientes en la base de datos. Cada

instancia de cada clase es una entidad que representa una fila de cada tabal.

Cuando definimos nuestro modelo de datos, el diseñador LINQ to SQL creó una clase llamada DataContext que

proporciona todo lo necesario para poder consultar/actualizar  la base de datos. En nuestro ejemplo, esta clase se

llama NorthwindDataContext. Ésta clase tiene unas propiedades que representan cada tabla modelada de la base de

datos (en concreto: Products, Categories, Customers, Orders y OrderDetails).

Como vimos en el tercer post de esta serie, podemos usar expresiones LINQ para consultar y obtener datos usando la

clase NorthwindDataContext.LINQ to SQL traduce automáticamente estas expresiones LINQ al código SQL apropiado

en tiempo de ejecución.

Page 33: Usando Linq to SQL

Por ejemplo, la siguiente expresión devuelve un objeto Product buscando el nombre del  producto:

La siguiente consulta nos devuelve todos los productos de la base de datos que no han sido pedidos, y cuyo precio es

mayor de 100 dólares:

Estamos usando la asociación “OrderDetails” de cada producto como parte de la consulta sólo para obtener aquellos

productos que no se han pedido.

Seguir los cambios y DataContext.SubmitChanges()

Cuando creamos consultas y obtenemos objetos como en los ejemplos anteriores, LINQ to SQL estará pendiente de los

cambios o actualizaciones que les hagamos a los objetos. Podemos hacer tantas consultas y cambios como queramos

usando la clase DataContext de LINQ to SQL, sabiendo que dichos cambios serán supervisados a la vez:

Nota: El seguimiento de cambios de LINQ to SQL ocurre en el lado del consumidor – y NO en la base de datos. Es decir, no estamos

consumiendo ningún recurso de la base de datos mientras lo usemos, tampoco tenemos que cambiar/instalar nada en la base de

datos para que esto funcione.

Después de realizar los cambios que queramos a los objetos que hemos obtenido con LINQ to SQL, podemos llamar al

método “SubmitChanges()” de nuestro DataContext para guardar los cambios en nuestra base de datos. Con esto,

LINQ to SQL, creara y ejecutará las sentencias SQL apropiadas para actualizar la base de datos.

Por ejemplo, el siguiente código actualiza el precio y las unidades en stock del producto “Chai” en la base de datos:

Page 34: Usando Linq to SQL

Cuando llamamos al método northwind.SubmitChanges(), LINQ to SQL creará y ejecutará las sentencias “UPDATE” de

SQL necesarias para guardar las propiedades modificadas.

Con el siguiente código iteramos sobre los productos menos populares y caros y ponemos la propiedad “ReorderLevel”

a cero.

Cuando llamamos al método northwind.SubmitChanges(), LINQ to SQL crea y ejecuta las sentencias UPDATE de SQL

necesarias para modificar los productos a los que hemos modificado la propiedad ReorderLevel.

Vemos que si no se ha modificado alguna propiedad de un Product con la asignación anterior, LINQ to SQL no

ejecutará ninguna actualización para ese objeto. Por ejemplo – si el precio del producto “Chai” era 2 dolares, y el

número de unidades en stock era cuatro, la llamada a SubmitChanges() no actualizara esos valores. Sólo los productos

cuyo ReorderLevel no era 0 se actualizarán.

Ejemplos de inserción y borrado

Además de poder actualizar la base de datos, LINQ to SQL también nos permite insertar y eliminar datos. Esto lo

conseguimos añadiendo o eliminando objectos de las colecciones disponibles en DataContest, y luego llamar al

método SubmitChanges(). LINQ to SQL “monitorizará” esas inserciones y borrados, y generará el código SQL necesario

cuando se invoque a SubmitChanges()

Añadiendo un producto

Podemos añadir un producto a la base de datos creando un nuevo objeto “Product”, inicializando sus propiedades y

añadirlo a la colección “Products” de nuestro DataContext:

Page 35: Usando Linq to SQL

Cuando llamemos a SubmitChanges() se añadirá una nueva fila en la tabla de productos.

Borrando productos

De la misma forma que añadimos un nuevo producto a la base de datos añadiendo un objeto Product a la colección

Products del DataContext, también podemos borrar productos borrándolos de esa misma colección:

Lo que estamos haciendo es obtener una secuencia de productos “alternados” de la tabla, es decir, no ordenados por

ninguna expresión LINQ, y luego esa secuencia se la pasamos al método RemoveAll() de la colección “Products”.

Cuando llamamos a SubmitChanges() todos esos productos serán borrados de la tabla

Actualizaciones y relaciones

Lo que hace que los O/RM’s como LINQ to SQL sean tan flexibles es que también nos permiten modelar las relaciones

entre las tablas. Por ejemplo, podemos modelar que cada producto tenga una categoría, que cada pedido tenga un

detalle de pedido, asociar cada detalle de pedido con un producto, y tener un conjunto de pedidos en cada cliente. Ya

vimos cómo modelar las relaciones en la segunda parte de esta serie de post.

LINQ to SQL nos permite aprovechar estas relaciones tanto para consultar como para actualizar nuestros datos. Por

ejemplo, con el siguiente código creamos un nuevo producto y lo asociamos con la categoría “Beverages”:

Page 36: Usando Linq to SQL

Estamos añadiendo el objeto producto en la colección de categorías de productos. Esto indicará que hay una relación

entre dos objetos, y hará que LINQ to SQL mantenga automáticamente las relaciones de clave primaria/ajena entre los

dos cuando llamemos a SubmitChanges().

Veamos otro ejemplo para ver cómo LINQ to SQL nos ayuda a mantener limpio el código referente a las relaciones

entre las tablas. En el siguiente ejemplo estamos creando un nuevo pedido para un cliente existente. Después de

rellenar las propiedades necesarias, podemos crear dos objetos de detalles de pedido y asociarlo a un pedido de un

cliente y actualizaremos la base de datos con todos los cambios:

Page 37: Usando Linq to SQL

Como vemos, el modelo de programación que hemos usado para hacer todo esto es realmente limpio y orientado a

objetos.

Transacciones

Una transacción es un servicio de la base de datos que garantiza que un conjunto de acciones individuales van a

suceder de forma atómica – es decir, o se pueden completar todas o si hay alguna que falle, todas las demas se

descartarán, y el estado de la base de datos será el mismo que ántes de comenzar la transacción.

Cuando llamemos a SubmitChanges(), las actualizaciones se mapean en una única transacción. Es decir, la base de

datos no tendrá nunca un estado inconsistente si hacemos muchos cambios – tanto si se hacen las actualizaciones

como si no.

Si no hay ninguna transacción en curso, el objeto DataContext empezará una transacción de la base de datos para

guardar las actualizaciones que hagamos con SubmitChanges(). Pero LINQ to SQL también nos permite definir

explícitamente y usar nuestro propio sistema de transacciones (introducido en la versión 2.0 de .NET). Esto hace más

fácil aún integrar código LINQ to SQL con el código de acceso a datos que ya tengamos. También nos permite encolar

recursos que no son propios de la base de datos en la misma transacción - por ejemplo: podemos enviar un mensage

MSMQ, actualizar el sistema de archivos (usando el nuevo soporte transaccional de sistemas de archivos), etc – y

enlazar todas estas tareas en una sola transacción a la hora de actualizar la base de datos

Validación y lógica de negocio

Una de las cosas más importantes que los desarrolladores tienen que hacer cuando trabajan con datos es incorporar

validación  y reglas de negocio. LINQ to SQL tiene varias formas para hacer que los desarrolladores puedan hacer eso

de forma fácil y clara.

LINQ to SQL nos permite añadir esta validación lógica una vez. De forma que no tendremos que repetir esa lógica en

varios sitios, con lo que conseguimos un modelo de datos más mantenible y más claro.

Soporte de validación de esquemas

Cuando definimos el modelo de clases de datos con el diseñador de LINQ to SQL de VS 2008, se añadirán algunas

reglas de validación obtenidas del esquema de las tablas de la base de datos.

Los tipos de datos de las propiedades de las clases del modelo de datos coincidirán con el esquema de la base de

datos. Con esto tendremos errores de compilación si intentamos asignar un booleano a un valor decimal, o si

convertirmos tipos numéricos incorrectamente.

Si una columna en la base de datos está marcada como nullable, la propiedad correspondiente que crea el diseñador

de LINQ to SQL será un tipo nullable. Las columnas marcadas como no nullables lanzarán excepciones si no les

Page 38: Usando Linq to SQL

asignamos ningun valor. LINQ to SQL también se asegurará que de que los valores identidad/unicos se asignan

correctamente.

Obviamente podemos usar el diseñador LINQ to SQL para sobreescribir los valores por defecto del esquema si

queremos – pero por defecto, las tendremos automáticamente sin tener que hacer nada. LINQ to SQL también

comprueba los valores de los parámetros de las consultas SQL, de manera que no tendremos que preocuparnos por

los ataques de inyección de SQL.

Soporte para validación personalizada de propiedades

La validación de datos a través de esquemas es muy útil, pero no suele ser suficiente en escenarios reales.

Imaginemos que en la base de datos Northwind tenemos una propiedad “Phone” en la clase “Customer” que está

definida en la base de datos como nvarchar. Usando LINQ to SQL podemos escribir el siguiente código para

actualizarlo con un número de teléfono válido:

El problema que nos encontraríamos, sería que el siguiente código sigue siendo válido desde el punto de vista de un

esquema SQL (ya que sigue siendo una cadena, no un número de teléfono válido).

Para no permitir que no se puedan meter números de teléfono erróneos en nuestra base de datos, podemos añadir

una regla de validación personalizada a la clase Customer de nuestro modelo de datos. Es realmente fácil, todo lo que

necesitamos hacer es añadir una nueva clase parcial a nuestro proyecto que defina el siguiente método:

Page 39: Usando Linq to SQL

Este código usa dos caracteristicas de LINQ to SQL:

1. Todas las clases que genera el diseñador LINQ to SQL son “parciales” – es decir, podemos añadir métodos

adicionales, propiedades, y eventos (en archivos separados). Así podemos extender nuestro modelo de clases

creada por el diseñador de LINQ to SQL con reglas de validación y métodos auxiliares que definamos. No es

necesario ninguna configuración.

2. LINQ to SQL expone una serie de puntos de extensión en el modelo de datos que podemos usar para añadir

validación lógica. Muchos de estos puntos de extensión usan la nueva característica llamada “métodos parciales”

que viene con VB y C# en VS 2008 Beta2. Wes Dyer el equipo de C# ha escrito un post explicando cómo va esto

de los métodos parciales.

En nuestro ejemplo de validación, estamos usando el método parcial OnPhoneChangin que se ejecuta cada vez que se

cambia el valor de la propiedad ”Phone” de un objeto “Customer”. Podemos usar este método para validar la entrada

de datos (en este caso estamos usan una expresión regular). Si todo va bien, LINQ to SQL asumirá que el valor es

válido. Si hay algún problema con el valor, podemos lanzar una excepción en el método de validación – que hará que

la asignación no se haga.

Soporte para validación personalizada de objetos entidad.

En el punto anterior hemos visto cómo añadir validación a una propiedad individual de nuestro modelo de datos. Sin

embargo, algunas veces, necesitamos/queremos validar validar multiples propiedades de un objeto.

Veamos un ejemplo, tenemos un objeto Order y queremos poner las propiedades “OrderDate” y “RequiredDate”:

Page 40: Usando Linq to SQL

Este código es legal desde el punto de vista de SQL – aunque no tenga ningún sentido la propiedad de fecha de

entrega, que era para ayer.

LINQ to SQL en Beta2 nos permite añadir reglas de validación a nivel de entidad para corregir este tipo de errores.

Podemos añadir una clase parcial para nuestra entidad “Order” e implementar el método parcial OnValidate() que se

invocará ántes de que se guarden los datos en la base de datos. De esta forma, podemos acceder y validar todas las

propiedades de nuestro modelo de datos:

De esta forma podemos validar cualquiera de las propiedades de la entidad (incluso obtener acceso de sólo lectura a

los objetos asociados), y lanzar una excepción si el valor es incorrecto. Cualquier excepción lanzada desde el método

OnValidate() abortará cualquier cambio que queramos hacer en la base de datos, y deshacer todos los cambios

hechos en la transacción actual.

Validación en los métodos de inserción/actualización/borrado.

A menudo necesitamos añadir validación específica en los métodos de inserción, actualización o borrado. LINQ to SQL

nos lo permite añadiendo una clase parcial que extienda a la clase DataContext e implementar métodos parciales para

personalizar la lógica de inserción, actualización y borrado de las entidades de nuestro modelo de datos. Estos

métodos serán llamados automáticamente cuando invoquemos a SubmitChanges().

Podemos añadir la validación lógica que estimemos oportuna con estos métodos – y si todo va bien, LINQ to SQL

continará guardando los datos en la base de datos (llamando al método de DataContext “ExecuteDynamicXYZ”).

Page 41: Usando Linq to SQL

Podemos añadir métodos que se invocarán automáticamente cuando se vayan a crear/actualizar/borrar datos. Por

ejemplo, supongamos que queremos crear un nuevo pedido y asociarlo con un cliente existente:

Cuando llamamos a northwind.SubmitChanges(), LINQ to SQL determinará que es necesario guardar el nuevo objeto

Order, y ejecutará nuestro método parcial “InsertOrder”.

Avanzado: Viendo la lista de cambios de la transacción

Page 42: Usando Linq to SQL

Hay veces que no nos interesa añadir validación lógica a elementos individuales, sino que queremos ser capaces de

ver toda la lista de cambios que están ocurriendo en una transacción.

Desde la Beta2 de .NET 3.5, LINQ to SQL nos permite acceder a la lista de cambios a través del método

DataContext.GetChangeList(). Nos devolverá un objeto ChangeList que expone una serie de colecciones de adiciones,

borrados y modificaciones que se han hecho.

Una aproximación que podemos hacer en algunos escenarios es crear una clase parcial de la clase DataContext y

sobreescribir su método SubmitChange(). Podemos obtener la lista de ChangeList() para las operaciones de

actualizaciones y crear cualquier validación que queramos:

Este ejemplo es un caso de uso avanzado – pero es interesante saber que siempre podremos extender y

aprovecharnos de esta forma de las nuevas características de LINQ to SQL.

Administrando cambios simultáneos con concurrencia optimista.

Una de las cosas en las que tenemos que pensar los desarrolladores en entornos multi-usuarios es cómo administrar

las actualizaciones de los mismos datos en la base de datos. Por ejemplo, imaginemos que tenemos dos usuarios que

obtienen un objeto product, y uno de ellos cambia el ReorderLevel a 0 mientras que el otro lo pone a 1. Si ambos

usuarios guardan esos cambios en la base de datos, el desarrollador tiene que decidir cómo tratar ese conflicto.

Una solución es dejar que sea el último que lo guarda – es decir, que el valor que el primer usuario guardó se perderá

sin que éste se de cuenta. Esta es una solución muy pobre (e incorrecta).

Otra solución que permite LINQ to SQL es usar el modelo de concurrencia optimista, es decir, LINQ to SQL detectará

automáticamente si el valor original de la base de datos ha sido actualizado por alguien ántes que se guarden los

nuevos datos. LINQ to SQL nos da una lista de conflictos de valores cambiados al desarrollador y nos permite tanto

Page 43: Usando Linq to SQL

hacer lo que queramos como avisar al usuario de la aplicación para que nos indique el propio usuario lo que quiere

hacer.

Ya veremos en más detalle este tema en un próximo post.

Uso de procedimientos almacenados o lógica SQL personalizada para insertar, actualizar y borrar.

Una de las preguntas que tienen los desarrolladores (en especial los DBAs), que suelen escribir procedimientos

almacenados con SQL personalizadas, cuando ven LINQ to SQL por primeravez es: “¿pero cómo podemos tener control

absoluto del SQL que se está ejecutando?”.

Las buenas noticias son que LINQ to SQL tiene un modelo muy flexible que nos permite sobreescribir el SQL que se

está ejecutando, y llamar a los procedimientos almacenados que desarrollemos para añadir, actualizar o borrar datos.

Lo realmente increible es que podemos empezar definiendo nuestro modelo de datos y dejar que LINQ to SQL

administre las inserciones, actualizaciones y borrados. Una vez hecho esto, podemos personalizar el modelo de datos

para que use nuestros propios procedimientos almacenados o nuestras sentencias SQL – sin tener que cambiar nada

de la lógica de aplicación que estamos usando para nuestro modelo de datos, ni cambiar nada de las validaciones ni

de la lógica de negocio. Esto nos da una gran flexibilidad a la hora de construir nuestra aplicación.

Dejaremos para otro post cómo personalizar los modelos de datos con procedimientos almacenados o sentencias SQL.

Resumen.

Este post presenta un buen resumen sobre cómo podemos usar LINQ to SQL para actualizar nuestra base de datos e

integrar de una forma clara validación de datos y lógica de negocio. Creo que encontraréis que LINQ to SQL

incrementa mucho la prouctividad a la hora de trabajar con datos, y nos permite escribir código orientado a objeto

claro en el acceso a datos.

LINQ to SQL (5ª Parte) – Enlazar controles de interfaz de usuario con el   ASP:LinqDatSource

Publicado en .NET, ASP .NET, LINQ, LINQ to SQL, Scott Guthrië, SQL, Visual Studio a 10:43 pm por Juanma

En las últimas semanas he escrito una serie de post sobre LINQ to SQL. LINQ to SQL es un O/RM que viene con la

versión 3.5 del framework .NET, y nos permite modelar bases de datos relacionales con clases de .NET. Podemos usar

expresiones LINQ para consultar la base de datos, así como actualizar, insertar y borrar datos.

Aquí tenéis los links a los post anteriores:

Parte 1: Introducción a LINQ to SQL

Parte 2: Definiendo el modelo de datos.

Parte 3: Consultando la base de datos

Page 44: Usando Linq to SQL

Parte 4: Actualizando la base de datos.

En estos post hemos visto cómo podemos usar LINQ to SQL programáticamente para consultar y actualizar nuestra

base de datos.

En el post de hoy veremos el nuevo control <asp:LinqDataSource> de la nueva versión del .NET Framework (3.5). Este

control es una nueva fuente de datos para ASP.NET (como los controles ObjectDataSource y SQLDataSource de

ASP.NET 2.0) que nos va a permitir enlazar controles de la interfaz de usuario a nuestro modelo de datos LINQ to SQL.

Aplicación de ejemplo que construiremos.

El ejemplo que veremos se trata de una aplicación muy simple que nos va a permitir editar los datos de la tabla

products:

La aplicación le da al usuario las siguientes opciones de gestión:

Page 45: Usando Linq to SQL

1. Filtrado de productos por categorías.

2. Ordenar los productos haciendo clic en la cabecera de las columnas (Nombre, Precio, unidades en stock, etc)

3. Navegar en por los productos de 10 en 10.

4. Edición de los detalles de cualquier producto.

5. Borrar productos de la lista.

La aplicación web la implementaremos con un modelo de datos muy limpio creado con el ORM LINQ to SQL.

Todas las reglas de negocio y las validaciones lógicas se implementarán en el la capa de datos – y no en la capa de

presentación ni en ninguna página web. Con esto conseguiremos: 1) Un conjunto consistente de reglas de negocio que

serán usadas en toda la aplicación, 2) escribiremos menos código y mejor aún, no lo repetiremos y 3) podremos

cambiar las reglas de negocio cuando queramos sin tener que actualizar ese código en miles de sitios en toda la

aplicación.

También aprovecharemos el soporte de paginado y ordenación de LINQ to SQL para asegurarnos que tales

operaciones no se realizan en la capa intermedia, sino en la base de datos (es decir, sólo obtendremos 10 productos

de la base de datos en cada momento – no estamos obteniendo miles de filas y ordenándolas/paginándolas en el

servidor web).

¿Qué es el control <asp:LinqDataSource> y cómo nos ayuda?

El control <asp:LinqDataSource> es un control de ASP.NET que implementa elpatrón DataSourceControl que se

introdujo con ASP.NET 2.0. Es similar a los controles ObjectDataSource y SqlDataSource en que puede enlazar un

control ASP.NET en una página con la base de datos. La diferencia es que en lugar de enlazar directamente con la

base de datos (como el SqlDataSource) o a una clase genérica (como el ObjectDataSource), este control está diseñado

para enlazar aun modelo de datos con LINQ.

Una de las ventajas de usar este control es que nivela la flexibilidad de los ORMs basados en LINQ. No tenemos que

definir métodos para inserción/consulta/actualización y borrado para el datasource – sino que añadimos éste control a

nuestro modelo de datos, definimos con qué entidades queremos que trabaje, y enlazamos cualquier control de

ASP.NET para que trabaje con él.

Por ejemplo, para tener un listado básico de los productos que use las entidades Product con un modelo de datos LINQ

to SQL, sólo tenemos que declarar un control <asp:linqdatasource> en nuestra página que enlaze a la clase

datacontext de nuestro LINQ to SQL, identificar las entidades (por ejemplo: Products). Y ya podemos enlazar un

GridView con él (modificando su propiedad DataSourceID) para obtener un grid como el siguiente:

Page 46: Usando Linq to SQL

Sin tener que hacer nada más, podemos ejecutar la página y tener un listado de los productos con paginado y

ordenación. Podemos añadir los botones edit y delete en el grid y tener soporte automático para ello. No tenemos que

añadir ningún método, mapear ningún parámetro, ni escribir ningún código para el control <asp:LinqDataSource>

para tener todas estas operaciones. Cuando se hacen actualizaciones, el ORM se asegurará de que todas las reglas de

negocio y de validación que hemos añadido se cumplan ántes de guardar los datos.

Importante: La belleza de LINQ y LINQ to SQL es que obviamente no sólo sirven para escenarios como el anterior – o para casos

particulares para enlazar controles de interfaces de usuario como con el LinqDataSource. Como ya hemos visto en los post

anteriores, escribir código con este ORM es muy limpio. Siempre podemos escribir código personalizado para nuestras interfaces de

usuario que trabajen directamente con el modelo de LINQ to SQL si queremos o cuando nos encontremos en un escenario en el que

no se pueda usar <asp:linqdatasource>

En los siguientes pasos veremos como montar la aplicación que hemos descrito usando LINQ to SQL y el control

<asp:LinqDataSource>

Paso 1: Definir nuestro modelo de datos

Empezaremos definiendo el modelo de datos que usaremos para representar la base de datos.

Vimos cómo definirlo en la segunda parte   de estos artículos. Aquí tenéis una captura de pantalla de las clases del

modelo de datos creado con el diseñador de LINQ to SQL de la base de datos “Northwind”:

Page 47: Usando Linq to SQL

Volveremos sobre nuestro modelo de datos en el paso 5 de este tutorial cuando añadamos algunas reglas de

validación de negocio. Pero para empezar usaremos el modelo de arriba.

Paso 2: Creación de un listado básico de productos.

Empezaremos a crear la interfaz con una página ASP.NET con un control <asp:gridview> con algun estilo css:

Page 48: Usando Linq to SQL

Podríamos escribir código para enlazar programáticamente nuestro modelo de datos al GridView (como hicimos en la

tercera parte de la serie), o podemos usar el control <asp:linqdatasource> para enlazar el GridView al modelo de

datos.

VS2008 nos permite enlazar nuestro GridView (o cualquier control de servidor ASP.NET) gráficamente a datos LINQ.

Para hacerlo tenemos que pasar a la vista de diseño, seleccionar el GridView y elegir la opción “New Data Source …”

en “Choose Data Source”:

Esto nos mostrará un cuadro de diálogo con una lista de fuentes de datos disponibles. Seleccionamos la nueva opción

“LINQ” y le damos el nombre que queramos:

El diseñador del control <asp:linqdatasource> nos mostrará las clases DataContext de LINQ to SQL que hay

disponibles (incluyendo aquellas que están en las librerías que tengamos referenciadas):

Page 49: Usando Linq to SQL

Seleccionaremos el modelo que creamos con el diseñador de LINQ to SQL. Seleccionaremos la tabla que queramos

que sea la entidad principal con la que enlazar el grid. En nuestro caso seleccionaremos la clase Products. También

seleccionamos el boton “Advanced” y habilitaremos las actualizaciones y borrados para la fuente de datos:

Page 50: Usando Linq to SQL

Cuando hagamos clic en el botón “Finish”, VS 2008 declarará un contorl <asp:linqdatasource> en el .aspx y

actualizará el gridview para que use esta fuente de datos. También generará las columnas necesarias para los

diferentes campos de la clase Product:

Ahora desplegamos el “smart task” del grid view y le indicamos que queremos habilitar la paginación, ordenado,

edición y borrado:

Podemos pular F5 para ejecutar la aplicación, y veremos una página con el listado de productos con paginación y

ordenado:

Page 51: Usando Linq to SQL

También podemos pulsar los botones “edit” o “delete” en cada fila para actualizar los datos:

Si pasamos a la vista de código de la página, veremos las marcas que contiene. El control <asp:linqdatasource>

apunta a la clase DataContext, y a la tabla que le dijimos al principio. El GridView tiene como fuente de datos el

control <asp:linqdatasource> (en el DatasourceID) y le indica qué columnas tienen que incluirse en el grid, cuál es el

texto de la cabecera, y cual es la expresión de ordenación:

Page 52: Usando Linq to SQL

Ahora tenemos lo básico para empezar a trabajar con el comportamiento de esta interfaz de usuario.

Paso 3: Limpiando las columnas.

El grid tiene muchas columnas, y dos de ellas (el SupplierId y el CategoryID) son claves ajenas, que no conviene

mostrar al usuario.

Eliminando columnas innecesarias

Empezaremos eliminando alguna de las columnas que no necesitamos. Podemos hacer esto en la vista de

código(borrando la declaración de <asp:boundfield> correspondiente)  o en la vista de diseño (haciendo clic en la

columna y seleccionando la tarea “remove”). Por ejemplo, podemos eliminar la columna “QuantityPerUnit” y ejectuar

la aplicación:

Page 53: Usando Linq to SQL

Si hemos usado el contorl <asp:ObjectDataSource> y le hemos indicado explícitamente los parámetros de

actualización (update) a los métodos de actualización (por defecto cuando usamos un DataSet basado en

TableAdapters) una de las cosas que tenemos que hacer es cambiar la firma de los métodos de actualización del

TableAdapter. Por ejemplo: si eliminamos una columnan del grid, tenemos que modificar el TableAdapter para que

soporte los métodos de actualización sin parámetros.

Con el control <asp:LinqDataSource> es que no tendríamos que hacer este tipo de cambios. Simplemente borrando (o

añadiendo) una columna a la interfaz de usuario y ejecutamos la aplicación -no hacen falta más cambios. Con esto

conseguimos que los cambios que se hagan en la interfaz de usuario sean mucho más fáciles, y nos permite

iteraciones más rápidas en nuestra aplicación.

Limpiando las columnas SupplierId y CategoryID

Hasta ahora estamos mostrando valores enteros de las claves ajenas en nuestro GridView para los campos Supplier y

Category:

Desde el punto de vista del modelo de datos es correcto, pero no desde el punto de vista del usuario. Lo que

queremos hacer es mostrar el nombre de la categoría y el nombre del proveedor, y mostrar una lista desplegable en

modo edición para que podamos cambiar estas asociaciones de forma fácil.

Page 54: Usando Linq to SQL

Podemos cambiar el gridview para que muestre el nombre del proveedor y el de la categoría en lugar del ID,

cambiando el <asp:BoundField> por un <asp:TemplateField>. Y en este templateField añadimos el contenido que

queramos para personalizar la vista de la columna.

En el código siguiente aprovecharemos la capacidad de LINQ to SQL, que modeló este campo como una propiedad. Es

decir, posdemos enlazar de forma fácil las propiedades Supplier.CompanyName y Category.CategoryName al grid:

Ahora ejecutamos la aplicación y tenedremos los valores de Category y Supplier de la siguiente forma:

Page 55: Usando Linq to SQL

Para tener una lista desplegable en estos dos campos en el modo edición, tenemos que añadir dos controles

<asp:LinqDataSource> a la página. Los configuraremos para que se enlacen a las entidades Categories y Suppliers del

modelo de datos creado por LINQ to SQL:

Ahora volvemos a la columnas <asp:TemplateField> que añadimos antes y personalizaremos la parte de edición

(especificando un EditItemTemplate). De forma que tendremos una lista desplegable en la vista edición, donde los

valores disponibles se obtendrán de las fuentes de datos de categorías y proveedores, y enlazaremos doblemente el

valor seleccionado al SupplierId y CategoryID de las claves ajenas:

Page 56: Usando Linq to SQL

Y ahora, cuando el usuario haga clic en el botón de edición, se mostrará una lista con todos los proveedores

disponibles:

Y cuando salvemos los cambios  se guardará el valor seleccionado en la lista desplegable.

Paso 4: Filtrando el listado de productos.

Más que mostrar todos los productos de la base de datos, podemos actualizar la interfaz de usuario para incluir una

lista desplegable que permita al usuario filtrar los productos por una categoría particular.

Como ya añadimos un <asp:LinqDataSource> enlazada a las Categorías de nuesto modelo de LINQ to SQL, sólo

tendremos que crear un nuevo control de lista desplegable y enlazarlo. Por ejemplo:

Page 57: Usando Linq to SQL

Cuando ejecutemos la página tendremos un filtro con todas las categorías al principio de la página:

Lo último que queda es que cuando seleccionemos una categoría se muestren los productos de dicha categoría en el

gridview. Lo más facil es seleccionar la opción de “Configure DataSource” en el smart task del GridView:

Con esto veremos el cuadro de dialogo para configurar el <asp:LinqDataSource> que usamos al principio del tutorial.

Seleccionamos el botón “Where” para añadir un campo de filtro al datasource. Podemos añadir cualquier número de

expresiones, y declarativamente asignar los valores con los que filtrar (por ejemplo: de una querystring, de valores de

formulario, de cualquier control en la página, etc).

Page 58: Usando Linq to SQL

Vamos a poner un filtro de productos por su CategoryID, y obtenemos el valor con el que filtrar de la lista desplegable

que creamos antes:

Page 59: Usando Linq to SQL

Cuando le damos a “Finish”, el contorl <asp:linqdatasource> se actualizará para reflejar los cambios de filtrado:

Y cuando ejecutamos la aplicación el usuario será capaz de elegir una categoría en la lista de filtrado y paginar,

ordenar, editar y borrar los productos de una categoría:

Page 60: Usando Linq to SQL

El control <asp:LinqDataSource> aplicará las expresiones LINQ necesarias para que  cuando se ejecute contra el

modelo de datos LINQ to SQL sólo se obtengan los datos necesarios de la base de datos (por ejemplo: en el grid

anterior sólo obtendremos 3 filas con los productos de la categoría Confection).

También podemos gestionar nosotros el evento Selecting si queremos escribir expresiones LINQ personalizadas.

Paso 5: Añadir reglas de validación de negocio

Como ya vimos en la cuarta parte   de esta serie de post, cuando definimos modelos de datos con LINQ to SQL

tendremos un conjunto de esquemas de validación por defecto en el modelo de clases. Es decir, si intentamos meter

un valor nulo en una columna requerida, intentar asignar un string a un entero, o asignar una valor de clave ajena en

una fila que no exista, el modelo lanzará un error y se asegurará de que la integrar de la base de datos se mantiene.

El esquema básico de validación es sólo el primer paso, y es muy raro en la mayoría de aplicaciones reales.

Normalmente necesitaremos añadir reglas adicionales a nuestro modelo de datos. Afortunadamente con LINQ to SQL

podemos añadir estas reglas de forma muy fácil (para más detalles sobre este tema, leed la cuarta parte   de esta serie

de post).

Ejemplo de escenario con reglas de validación

Por ejemplo, supongamos una regla básica que queramos reforzar. Queremos que un usuario de nuestra aplicación no

pueda interrumpir un producto mientras haya unidades pedidas:

Si un usuario intenta guardar la fila anterior, queremos prevenir que ese cambio se guarde en la base de datos y que

genere un error para que el usuario lo arregle.

Añadiendo una regla de validación al modelo de datos.

El sitio incorrecto para añadir este tipo de validación es en la capa de presentación. Añadirlo en esta capa implica que

esta regla será sólo válida en un lugar concreto, y no será automático en cualquier parte de la aplicación. Distribuir la

lógica de negocio en la capa de presentación también hará que nuestra vida sea realmente penosa a medida que

Page 61: Usando Linq to SQL

nuestra aplicación crezca – ya que cualquier cambio/actualización en nuestro negocio hara necesarios cambios de

codigo en todas partes.

El lugar correcto para este tipo de validación es en las clases del modelo de datos de LINQ to SQL. Como ya vimos en

la cuarta parte   de esta serie, todas las clases se generan por el diseñador de LINQ to SQL como clases parciales – con

lo que podemos añadir métodos/eventos/propiedades fácilmente. El modelo de LINQ to SQL ejectuará los métodos de

validación que podemos implementar.

Por ejemplo, Podemos añadir una clase parcial Product a nuestro proyecto que implemente el método parcial

OnValidate() que LINQ to SQL llama antes de guardar las entidades de Product. En este método podemos añadir la

siguiente regla de negocio para segurarnos que los productos no pueden tener un Reorder Level si el producto es

discontinued:

Una vez que añadimos la clase anterior al proyecto LINQ to SQL, la regla anterior se comprobará cada vez que alguien

use nuestro modelo de datos e intente modificar la base de datos. Esto se hace tanto para los productos existentes

que se vayan a actualizar como para los que se vayan a añadir nuevos.

Como el <asp:LinqDAtaSource> trabaja contra nuestro modelo de datos, cada actualización/inserción/borrado pasará

por esta regla de validación antes de guardar los cambios. No necesitamos hacer nada más en la capa de

presentación para que se cumpla esta regla – se comprobará cada vez que se use nuestro modelo de datos.

Añadir un manejador de errores en la capa de presentación.

Por defecto si un usuario usa nuestro GridView para meter una combinación no válida de  UnitOnOrder/Discontinued,

nuestro modelo LINQ to SQL lanzará una excepción. El <asp:LinqDataSource> capturará la excepción y nos

proporciona un evento que podemos usar para controlarlo. Si nadie usa el evento, el contol GridView (u otro) enlazado

al <asp:LinqDataSource> capturará el error y proveerá un evento para controlarlo. Si nadie controla el error será

pasado al manejador d ela página, y si nadie lo controla, se le pasará al evento Application_Error() en el archivo

Global.asax. Los desarrolladores pueden hacer esto en cualquier paso del camino para añadir la lógica de errores que

queramos en la capa de presentación.

Para la aplicación que estamos viendo, seguramente el mejor lugar para controlar cualquier error de actualización sea

en el vento rowUpdated del gridView. Este evento se ejectuará cada vez que se actualize en nuestro datasource, y

Page 62: Usando Linq to SQL

podemos ver los detalles de la excepción si falla la actualización. Podemos añadir el siguiente código para comprobar

si ha ocurrido un error, y mostrar un error adecuado en caso de que ocurra:

No hemos tenido que añadir ninguna validación lógica en nuestra interfaz de usuario. En lugar de eso, estamos

obteniendo el error que lanzamos en nuestra lógica de negocio y la estamos usando para mostrar un mensaje

adecuado al usuario (Estamos mostrando un error más genérico).

También le estamos indicando que queramos que el GridView se mantenga en el modo edición cuando ocurra un error

– de forma que podemos evitar que el usuario pierda los cambios que estaba haciendo, y modificar los valores y darle

a “update” otra vez e intentar guardarlo. Podemos añadir un control <asp:literal> en el “ErrorMessage” en cualquier

parte de la pagina que queramos para controlar donde queremos que se muestre el error:

Y ahora cuando intentemos actualizar un producto con valores erroneos veremos un mensaje de error que indica cómo

arreglarlo:

Page 63: Usando Linq to SQL

Lo bueno de esto es que podemos añadir o cambiar las reglas de negocio sin tener que cambiar nada en la capa de

presentación. Las reglas de validación, y sus mensajes correspondientes, pueden centralizarse en un lugar en concreto

del modelo de datos y se aplicarán en todas partes.

Resumen

El control <asp:LinqDataSource> nos da una forma fácil de enlazar controles de ASP.NET a nuestro modelo de LINQ to

SQL. Permite obtener/actualizar/insertar/borrar datos del modelo de datos.

En nuestra aplicación hemos usado el ORM LINQ to SQL para crear un modelo limpio, orientado a objetos. Añadimos

tres contorles ASP.NET a la página (un gridView, una lista desplegable, y un errormessage literal), y hemos añadido

tres contorles <asp:LinqDataSource> para enlazar a Product, Category y Proveedores:

Page 64: Usando Linq to SQL

Escribimos 5 líneas de validación lógica y 11 lineas para la gestión de errores.

El resultado final es una aplicación web simple que permite a los usuarios filtrar los productos por su categoría,

ordenar y paginar eficientemente dichos productos, editar los productos y guardarlos (con nuestra reglas de negocio),

y borrar productos del sistema (también con nuestra lógica de negocio).

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

Publicado en .NET, ASP .NET, LINQ, LINQ to SQL, Scott Guthrië, SQL a 3:07 pm por Juanma

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:

Page 65: Usando Linq to SQL

Parte 1: Introducción a LINQ to SQL

Parte 2: Definiendo el modelo de datos.

Parte 3: Consultando la base de datos

Parte 4: Actualizando la base de datos.

Parte 5: Enlazar controles de interfaz de usuario con el   ASP:LinqDatSource

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 puedeencapsular 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:

Page 66: Usando Linq to SQL

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:

Page 67: Usando Linq to SQL

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:

Page 68: Usando Linq to SQL

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:

Page 69: Usando Linq to SQL

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:

Page 70: Usando Linq to SQL

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:

Page 71: Usando Linq to SQL

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:

Page 72: Usando Linq to SQL

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”:

Page 73: Usando Linq to SQL

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:

Page 74: Usando Linq to SQL

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:

Page 75: Usando Linq to SQL

C#:

Soporte de funciones definidas por el usuario (UDFs)

Page 76: Usando Linq to SQL

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#:

Page 77: Usando Linq to SQL

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.

LINQ to SLQ (Parte 7 – Actualizando la base de datos con procedimientos   almacenados)

Publicado en .NET, ASP .NET, LINQ, LINQ to SQL, Scott Guthrië, SQL, Visual Studio a 12:51 am por Juanma

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:

Parte 1: Introducción a LINQ to SQL

Page 78: Usando Linq to SQL

Parte 2: Definiendo el modelo de datos.

Parte 3: Consultando la base de datos

Parte 4: Actualizando la base de datos.

Parte 5: Enlazar controles de interfaz de usuario con el   ASP:LinqDatSource

Parte 6: Obtener datos con procedimientos almacenados .

En la sexta parte vimos cómo podemos usar procedimientos almacenados (SPROCs) y funciones definidas por el

usuario (UDFs) para consultar la base de datos con el modelo de datos de LINQ to SQL. En el post de hoy veremos

cómo podemos usar los SPROCs para actualizar/insertar/borrar datos de nuestra base de datos.

Para ayudar a entender esto empezaremos costruyendo una capa de datos para la base de datos de ejemplo

Northwind:

Paso 1: Crear nuestra capa de acceso a datos (sin SPROCs)

En la segunda parte de esta serie   vimos cómo usar el diseñador de LINQ to SQL de VS 2008 para crear el siguiente

modelo de clases:

Page 79: Usando Linq to SQL

Añadiendo reglas de validación a nuestro modelo de clases.

Después de definir nuestro modelo querremos añadir reglas de validación a nuestro modelo de datos. Podemos hacer

esto añadiendo clases parciales a nuestro proyecto y añadir las reglas de validación en esas clases (vimos cómo hacer

esto en la cuarta parte de esta serie).

Por ejemplo, podemos añadir la lógica necesaria para asegurarnos de que el número de teléfono de los clientes siguen

un patrón válido, y otra para asegurarnos de que la fecha de entrega (RequierdDate) es posterior a la fecha actual del

pedido (OrderDate). Una vez que hemos definido las clases parciales, estos métodos de validación se ejecutarán cada

vez que escribamos código para actualizar nuestros objetos de datos de nuestra aplicación:

VB:

Page 80: Usando Linq to SQL

C#:

Page 81: Usando Linq to SQL

Añadir un método de ayuda GetCustomer() a nuestro DataContext

Una vez que hemos creado nuestro modelo de clases, y que le hemos añadido reglas de validación, podemos

consultar e interactuar con los datos. Podemos hacer esto escribiendo expresiones LINQ sobre nuestro modelo de

clases (vimos cómo hacer esto en la tercera parte de esta serie). También podemos mapear SPROCs en nuestro

DataContext (esto lo vimos en la sexta parte de la serie).

Cuando creamos una capa de datos con LINQ to SQL normalmente querremos encapsular consultas comunes de LINQ

(o SPROCs) en métodos auxiliares que añadiremos a la clase DataContext. Esto lo conseguimos añadiendo una clase

parcial a nuestro proyecto. Por ejemplo, podemos añadir un método llamado “GetCustomer()” que nos permita buscar

y obtener objetos Customer de la base de datos a partir del valor CustomerID:

VB:

Page 82: Usando Linq to SQL

C#:

Paso 2: Usando nuestra capa de datos (seguimos sin SPROCs)

Ya tenemos una capa de datos que encapsula nuestro modelo de datos, integra reglas de validación, y nos permite

consultar, actualizar, insertar y borrar datos.

Veamos ahora un escenario simple usándolo para obtener un objeto customer existente, actualizamos el ContactName

y el PhoneNumber, y creamos un nuevo objeto Order para asociarlos. El siguiente código hace todo eso en una sola

transacción. LINQ to SQL se asegura de que las reglas de validación se cumplen ántes de guardar nada en la base de

datos:

VB:

Page 83: Usando Linq to SQL

C#:

LINQ to SQL monitoriza todas las modificaciones de los objetos que hemos obtenido de la base de datos, y guarda los

objetos que añadimos. Cuando llamamos al método DataContext.SubmitChanges(), LINQ to SQL comprueba las reglas

que hemos establecido, y genera automáticamente la SQL que actualizará el registro de Customer e insertará un

nuevo registro en la tabla Orders

Page 84: Usando Linq to SQL

Un momento – Pensaba que este post iba sobre SPROCs

Si aún estais leyendo, os preguntaréis dónde están los SPROCs en este post. ¿Porque os estoy mostrando el código de

arriba que hace que se genere una SQL dinámica? ¿Por qué no os he enseñado cómo llamar a un SPROC para hacer

las inserciones/actualizaciones/borrados todavía?

La razón es que el modelo de programación de LINQ to SQL tanto para trabajar con objetos modelados mediante

SPROC es exactamente el mismo que con SQL dinámico. La manera en que añadimos validación lógica es

exactamente igual (así que todas las reglas que hemos añadido a nuestro modelo de datos se aplicarán también si

usamos SPROCs). El código anterior que hemos usado para obtener un cliente, actualizarlo y añadir un nuevo pedido

es exactamente igual tanto si usamos SQL dinámico como si usamos SPROCs.

Esta simetría en el modelo de programación es muy potente ya que no tenemos que aprender dos maneras diferentes

de hacer las cosas, ni tenemos que decidir al principio del proyecto qué técnica usar, si SPROC o no. Podemos

empezar usando el SQL dinámico que nos da LINQ to SQL para las consultas, inserciones, actualizaciones y borrados.

Podemos añadir reglas de validación a nuestro modelo. Y luego podemos actualizar el modelo de datos para usar

SPROCs – o no. El código y los test que escribamos contra las clases del modelo de datos serán exáctamente iguales.

De ahora en adelante veremos cómo podemos actualizar nuestro modelo de datos usando SPROCs para

actualizar/insertar/borrar – mientras seguimos usando las mismas reglas de validación y trabajaremos con los mismos

códigos anteriores.

Cómo usar SPROCs en inserciones, actualizaciones y borrados

Podemos modificar la capa de datos que estamos construyendo para que use SPROCs, en lugar de SQL dinámico de

dos maneras:

1. Usando el diseñador de LINQ to SQL para configurar gráficamente la ejecución de los SPROCs en las diferentes

operaciones o

2. Añadir una clase parcial NorthwindDataContext a nuestro proyecto, y entonces implementar los métodos

necesarios para la inserción, borrado y actualización. (por ejemplo: InsertOrder, UpdateOrder, DeleteOrder) que

serán llamados cuando se realize alguna de las operaciones asociadas. Estos métodos parciales serán pasados a

las instancias del modelo de datos que queramos actualizar, y podemos ejecutar tanto SPROC como código SQL

para guardarlo.

Cuando usemos la primera aproximación para configurar gráficamente los SPROCs que llamaremos, por debajo se está

generando el mismo código (en clases parciales que crea él solo) que escribiríamos si elegimos la segunda opción. En

general os recomiendo que uséis el diseñador de LINQ to SQL para configurar los SPROCs en el 90% de los casos – y

crear las llamadas personalizadas a procedimientos almacenados en escenarios más avanzados.

Paso 3: Hacer otras inserciones con un SPROC

Page 85: Usando Linq to SQL

Empezaremos cambiando nuestro modelo de datos para que use SPROCs con el objeto Order.

Primero nos vamos a la ventana de “Explorador de Servidores” (Server Explorer) de Visual Studio, expandimos el nodo

“Stored Procedures” de nuestra base de datos, hacemos clic con el botón derecho y elegimos la opción “Add New

Stored Procedure”:

Creamos el nuevo procedimiento almacenado que llamaremos “InsertOrder” que añade una nueva fila order a la tabla

Orders:

Page 86: Usando Linq to SQL

Fijáos que hemos definido el parámetro “OrderId” como un parámetro de salida. ESto es debido a que la columna

OrderID es una columna identidad que se autoincrementa cada vez que se añade un nuevo registro. Quien llame a

este SPROC deverá pasarle un valor null en ese parámetro – y el SPROC devolverá en ese parámetro el nuevo valor

OrderID (llamando a la función SCOPE_IDENTITY() al final del SPROC).

Después de crear el SPROC abrimos el diseñador de LINQ to SQL. De la misma forma que vimos en la sexta parte de

esta serie, podemos arrastrar y soltar SPROCs desde la ventana “server explorer” al diseñador. Esto es lo que haremos

con el nuevo SPROC que acabamos de crear:

Page 87: Usando Linq to SQL

El último paso será decirle a nuestra capa de datos que use el SPROC InsertOrder cuano inserter un nuevo objeto

Order en la base de datos. Esto lo hacemos seleccionando la clase “Order” del diseñador LINQ to SQL, y en las

propiedades clicamos el botón “…” del método Insert:

Page 88: Usando Linq to SQL

Hacemos clic en el botón “…” y aparecerá una ventana que nos permite personalizar las operaciones de inserción:

Page 89: Usando Linq to SQL

Fijaos cómo el modo po defecto (“Use Runtime”) está configurado para usar LINQ to SQL como generador dinámico de

las SQL. Para cambiarlo seleccionamos el radio buton “Customize” y seleccionamos el SPROC InsertOrder de la lista de

SPROCS disponibles:

El diseñador de LINQ to SQL calculará una lista de parametros para el SPROC que hemos seleccionado, permitiéndonos

mapear las propiedades de nuestra clase Order a los parámetros del SPROC InsertOrder. Por defecto seleccionará el

que más se parezca en el nombre. Podemos cambiarlo si queremos.

Una vez que cliquemos en OK está listo. Ahora cada vez que añadamos un nuevo pedido a nuestro DataContext e

invoquemos al método SubmitChanges(), se ejecutará el SPROC InsertOrder.

Importante: Aunque estemos usando SPROC para la persistencia, el método parcial “OnValidate()” que creamos (en la

primer parte de esta serie) para encapsular las reglas de validación para los pedidos seguirán ejecutándose antes de

realizar cualquier cambio. Es decir, tenemos una forma limpia de encapsular la lógica de negocio y las reglas de

validación en nuestros modelos de datos, y podemos reutilizarlos tanto si usamos SQL o SPROCS.

Paso 4: Actualizando los clientes con SPROCs.

Ahora vamos a modificar el objeto Customer para manejar las actualizaciones con un SPROC.

Page 90: Usando Linq to SQL

Empezamos creando el SPROC “UpdateCustomer”:

Fijaos que además de pasar el parámetro @CustomerID, también tenemos un parámetro @Original_CustomerID. La

columna CustomerID de la tabla Customers no es un campo autoincremental, y puede modificarse cuando hagamos

una actualización. Por tanto necesitamos ser capaces de decirle al SPROC cual es el CustomerID original y el nuevo

CustomerID. Vamos a ver cómo mapeamos esto con el diseñador de LINQ to SQL.

Veréis que estamos pasando un parámetro llamado @Version (que es una marca de tiempo) al SPROC. Es una nueva

columna que he añadido a la tabla Customers para ayudarme a controlar la concurrencia optimista. Veremos en más

detalle este tema en otro post de esta serie – pero en resumen es que LINQ to SQL soporta completamente la

concurrencia optimista, y nos permite usar tanto una marca de tiempo o usar valores original/nuevo para detectar si

ha habido algún cambio por parte de otro usuario ántes de guardar los datos. Para este ejemplo usaremos una marca

de tiempo ya que hace que el código sea mucho más claro.

Una vez que tenemos nuestro SPROC, lo arrastramos y soltamos al diseñador LINQ to SQL para añadirlo como método

a nuestro DataContext. Seleccionamos la clase Customer y hacemos clic en el botón “…” de la propiedad Update:

Page 91: Usando Linq to SQL

Seleccionamos el radio button “Customize” y seleccionamos el SPROC UpdateCustomer:

Page 92: Usando Linq to SQL

Cuando mapeamos las propiedades de los objetos Customer con los parámetros del SPROC, veremos que tenemos que

decidir si poner la propiedad “current” en el objeto de datos, o si poner el valor original que estaba en la base de datos

antes de obtener el objeto. Por ejemplo, tendremos que asegurarnos de que mapeamos el valor “current” de la

propiedad CustomerID en el parámetro @CustomerID, y el valor original en el parámetro @original_customerID.

Cuando hacemos clic en OK ya esta terminado. Ahora cuando actualizemos cualquier cliente y llamemos a

SubmitChanges() se ejectuará el SPROC UpdateCustomer en lugar de ejecutarse un SQL dinámico.

Importante: Aunque ahora estemos usando SPROC, el método parcial “OnPhoneChanging()” de la clase Customer (que

creamos en el primer post de esta serie) para validar los números de teléfono se seguirá ejecutando de la misma

manera ántes de que se guarden los cambios. Tenemos de esta forma una forma limpia de encapsular reglas de

negocio y validación a nuestros modelos de datos, y podemos reutilizarlos tanto si usamos SQL dinámico o SPROCs.

Paso 5: Usando el modelo de datos otra vez (esta vez con SPROCs)

Ahora que ya tenemos configurada nuestra capa de datos para usar SPOCs en lugar de SQL dinámico, podemos

ejecutar el mismo código que vimos en el paso 2:

Ahora las actualizacion del objeto Customer, y la inserción del objeto ORder, se están ejecutando a través de SPROCs

en lugar de SQL dinámico. La lógica de validación que definimos se siguen ejecutando como antes, y el código sigue

siendo exactamente el mismo.

Apuntes avanzados cuando usamos SPROCs

Page 93: Usando Linq to SQL

Veamos unas cuantas recomendaciones útiles para escenarios con SPROC más avanzados con LINQ to SQL

Uso de parámetros de salida

En casos de inserción (Paso 3) hemos visto cómo podemos devolver el nuevo valor OrderID (que es un valor

identidad y autoincremental de la tabla Orders) usando un parámetro de salida en el SPROC. No estamos limitados a

devolver sólo valores de columnas identidad con SPROCs y LINQ to SQL – en realidad podemos actualizar y devolver

cualquier parámetro. Podemos usarlo tanto para insetar como para actualizar. LINQ to SQL tomará el valor resultado y

actualizará la propiedad asociada en el modelo de dato sin que tengamos que hacer ninguna consulta extra para

refrescarlo o calcularlo de nuevo.

¿Que pasa si el SPROC da un error?

Si el SPROC da un error mientras inserta, actualiza o borra un dato, LINQ to SQL cancelará y deshará la transacción de

todos los cambios asociados a la llamada SubmitChanges(). De manera que nos aseguramos la consistencia de los

datos.

¿Podemos escribir código en lugar de usar el diseñador para llamar a un SPROC?

Como ya comenté al principio, podemos usar tanto el diseñador de LINQ to SQL para mapear las operaciones con

SPROC o podemos añadir métodos parciales a la clase DataContext programáticamente e invocarlos nosotros mismo.

Aquí tenéis un ejemplo del código que deberíamos escribir para sobreescribir el método UpdateCustomer de la clase

NorthwindDataContext:

Este código es el que fué generado con el diseñador de LINQ to SQL cuando lo usamos para mapear el SPROC y

asociarlo a la operación de Update del objeto Customer. Podemos usarlo como un punto de partida y añadir alguna

lógica adicional para hacerlo más personalizado (por ejemplo: usar el valor de retorno del SPROC para lanzar

excepciones personalizadas).

Resumen

LINQ to SQL es un ORM muy flexible. Nos permite escribir código limpio orientado a objetos para obtener, acutalizar e

insertar datos.

Page 94: Usando Linq to SQL

Lo mejor de todo es que nos permite diseñar una capa de datos realmente limpia e independiente de cómo se guardan

y cargan los datos de la base de datos. Podemos usar SQL dinámico o SPROCs para esas operaciones. Lo mejor es que

el código que use nuestra capa de datos, y todas las reglas de negocio asociadas, serán las mismas sin importar que

método de persistencia estemos usando.

LINQ to SQL (Parte 8 – Ejecutar consultas SQL   personalizadas)

Publicado en .NET, ASP .NET, LINQ, LINQ to SQL, Scott Guthrië, SQL, Visual Studio a 9:48 pm por Juanma

En las últimas semanas he escrito una serie de post sobre LINQ to SQL. LINQ to SQL es un ORM que viene con .NET

3.5, y nos permite modelar bases de datos relacionales en clases. Podemos usar expresiones LINQ para consultar la

base de datos y también para actualizar, insertar y borrar datos.

Aquí teneis los enlaces a los diferentes post de la serie:

Parte 1: Introducción a LINQ to SQL

Parte 2: Definiendo el modelo de datos.

Parte 3: Consultando la base de datos

Parte 4: Actualizando la base de datos.

Parte 5: Enlazar controles de interfaz de usuario con el   ASP:LinqDatSource

Parte 6: Obtener datos con procedimientos almacenados .

Parte 7: Actualizando la base de datos con procedimientos almacenados.

En los dos últimos post vismo cómo podemos usar los procedimientos almacenados de nuestra base de datos para

consultar, insertar, actualizar y borrar datos con el modelo de LINQ to SQL.

Una pregunta que me han hecho mucho desde que he escrito estos post es: ¿que pasa si quiero control total sobre las

consultas SQL que usa LINQ to SQL – pero no quiero usar SPROCs para hacerlo? En el post de hoy veremos eso – y

veremos cómo podemos usar expresiones SQL personalizadas para que LINQ to SQL las use en lugar de las que

generaría él.

Uso de expresiones LINQ con LINQ to SQL.

Supongamos que hemos usado el diseñador de LINQ to SQL de VS 2008 para modelar un conjunto de clases a partir de

la base de datos Northwind (esto lo vimos en el segundo post de la serie):

Page 95: Usando Linq to SQL

En el tercer post vimos cómo podemos usar LINQ con las nuevas características de VB y C# para consultar el modelo

de clases y devolver un conjunto de objetos que representan las filas y columnas de la base de datos.

Por ejemplo, podemos añadir un método a la clase DataContext “GetProductsByCategory” que usa una consulta LINQ

para devolver objetos de Products de la base de datos:

VB:

Page 96: Usando Linq to SQL

c#:

Una vez definido nuestro método de LINQ, podemos escribir el siguiente código para obtener productos e iterar sobre

ellos:

VB:

Cuando se evalúa la expresión LINQ del método “GetProductsByCategory”, el ORM LINQ to SQL ejectuará un SQL

dinámico para obtener los datos de la tabla Product para crear los objetos Product. Podeis usar el Visualizador de

Debug de LINQ to SQL   para ver en el debugger cuál es la expresión LINQ que se ejectuará.

Uso de consultas SQL personalizadas con LINQ to SQL

Page 97: Usando Linq to SQL

En el ejemplo de arriba no tenemos que escribir ningún código SQL para consultar y obtener objetos Product

fuertemente tipados. LINQ to SQL traduce la expresión LINQ a SQL por nosotros.

¿Pero que pasa si queremos un control total sobre el SQL que se está ejecutando en nuestra base de datos, y no

queremos que LINQ to SQL lo haga por nosotros? Una forma de conseguir esto es usando SPROC como ya vimos en las

partes 6 y 7 de esta serie. La otra forma es usar el método auxiliar “ExecuteQuery” de la clase DataContext y usar una

expresión SQL personalizada que le demos.

Usando el método ExecuteQuery

El método ExecuteQuery toma una expresión SQL como argumento , con un conjunto de parámetros, y la ejecuta

contra la base de datos (incluyendo JOINs personalizados sobre varias tablas.

Lo que hace que ExecuteQuery sea tan útil es que nos permite especifiar cómo queremos devolver los valores de la

expresión SQL. Podemos hacer esto pasándole un parámetro tipado al método o usando una versión genérica del

método.

Por ejemplo, podemos cambiar el método GetProductsByCategory() que creamos ántes -con una expresión LINQ- para

que use el método ExecuteQuery para ejectuar un SQL que nosotros le digamos:

VB:

C#:

Ahora podemos llamar al método GetProductsByCategory() de la misma forma que ántes:

Page 98: Usando Linq to SQL

De esta manera será nuestra consulta SQL la que se ejecutará contra la base de datos – y no el SQL dinámico que

generaría la expresión LINQ.

SQL personalizado y tracking de objetos para las actualizaciones

Por defecto cuando obtenemos objetos con LINQ to SQL, se hace un tracking sobre los cambios que les hacemos. Si

llamamos al método “SubmitChanges()” guardará los datos de forma transaccional en la base de datos. Vismo esto en

la cuarta parte de esta serie de post.

Una de las característcias del metodo ExecuteQuery() es que participa en este tracking de objetos para actualizar el

modelo. Por ejemplo, podemos escribir el siguiente código para obtener todos los productos de una categoría y rebajar

los precios un 10%:

Como dijimos que el tipo de resultado del ExecuteQuery en el método GetProductsByCategory fuese “Product, LINQ to

SQL sabe cómo guardar los cambios. Y cuando llamemos a SubmitChanges los guardará.

SQL personalizado con clases personalizadas.

Page 99: Usando Linq to SQL

El método ExecuteQuery nos permite especificar cualquier clase como tipo de resultado de la consulta SQL. La

clase no tiene porqué haberse creado con el diseñador LINQ to SQL, o implementar ninguna interfaz.

Por ejemplo, definimos la clase ProductSummary con un subconjunto de las propiedades de Product (fijáos que hemos

usado la característica depropiedades automáticas):

Podríamos crear otro método en nuestro DataContext llamado GetProductSummariesByCategory() que nos devuelva

objetos de esa clase. Fijáos cómo la siguiente SQL obtiene sólo un subconjunto de Product – El método ExecuteQuery()

se encarga de mapea automáticamente las propiedades a objetos de la clase ProductSumary:

Ahora podemos invocar a este método e iterar sobre los resultados con el siguiente codigo:

SQL personalizadas para inserciones, actualizaciones y borrados.

Además de usar SQL personalizadas para consultar datos, también podemos hacerlas para insertar, actualizar y borrar

datos.

Page 100: Usando Linq to SQL

Esto lo conseguimos creando los métodos parciales adecuados para cada operacion para la entidad que queramos

cambiar en nuestra clase DataContext. Podemos usar el método ExecuteCommand del DataContext para escribir el

SQL que queramos. Por ejemplo, para sobreescribir el comportamiento de borrado de la clase Product definimos el

siguiente método parcial:

Y si escribimos un código que elimine un producto de la base de datos, LINQ to SQL llamará al método DeleteProduct –

que ejecutará una SQL personalizada en lugar del SQL dinámico que LINQ to SQL usaría:

Resumen

El ORM LINQ to SQL genera y ejectua un SQL dinámico para las consultas, actualizaciones, inserciones y borrados

contra la base de datos.

Para escenarios más avanzados, o en caso donde queramos un control total sobre el SQL que se ejecuta, también

podemos personalizar el ORM para que ejecute SPROCs, o nuestras consultas SQL personalizadas. Esto nos da una

gran flexibilidad a la hora de construir y extender nuestra capa de datos.

LINQ to SQL (Parte 9 – Uso de expresiones LINQ personalizadas con el control   )

Publicado en .NET, ASP .NET, LINQ, LINQ to SQL, Scott Guthrië, SQL a 12:56 pm por Juanma

En las últimas semanas he escrito una serie de post sobre LINQ to SQL. LINQ to SQL es un ORM que viene con .NET

3.5, y nos permite modelar bases de datos relacionales en clases. Podemos usar expresiones LINQ para consultar la

base de datos y también para actualizar, insertar y borrar datos.

Aquí tenéis los enlaces a los diferentes post de la serie:

Page 101: Usando Linq to SQL

Parte 1: Introducción a LINQ to SQL

Parte 2: Definiendo el modelo de datos.

Parte 3: Consultando la base de datos

Parte 4: Actualizando la base de datos.

Parte 5: Enlazar controles de interfaz de usuario con el   ASP:LinqDatSource

Parte 6: Obtener datos con procedimientos almacenados.

Parte 7: Actualizando la base de datos con procedimientos almacenados.

Parte 8: Ejecutar consultas SQL personalizadas.

En la quinta parte vimos el control <asp:LinqDataSource> de .NET 3.5 y hablamos sbre cómo podemos enlazar

controles de ASP.NET a LINQ to SQL. También vimos cómo usarlo con el control <asp:ListView> (El control

asp:ListView (Parte 1 – Creación de una página de listado de productos con una CSS   limpia) )

En ambos artículos las consultas que hacíamos eran relativamente sencillas (la clausula where se ejecutaba sobre una

tabla simple). En el post de hoy veremos cómo usar toda la potecia de las consultas de LINQ con el control

LinqDataSource, y veremos cómo usar cualquier expresion LINQ to SQL con él.

Pequeña recapitulación: <asp:LinqDataSource> con una sentencia Where.

En estos dos   post  vimos cómo usar el filtro del control LinqDatasource para declarar un filtro en un modelo LINQ to

SQL.

Por ejemplo, supongamos que hemos creado un modelo LINQ to SQL de la base de datos Northwind (que ya vimos en

la segunda parte de esta serie), podríamos declarar un control <asp:LinqDataSource> en la página con un filtro

<where> que devuelve aquellos productos de una categoría dada. (especificada a partir del valor “categoryid”).

Luego, podemos enlazar un <asp:gridView> a este datasource y habilitar la paginación, edición y ordenación.:

Page 102: Usando Linq to SQL

Cuando ejecutamos la página anterior tendremos un GridView que soportará automáticamente la ordenación,

paginación y edición sobre el modelo de Produt:

Usando los parámetros del <where> de esta forma funciona muy bien en escenarios típicos. Pero ¿qué pasa si que el

filtrado de Product sea más complejo? Por ejemplo, ¿Si sólo queremos mostrar los productos suministrados por un

conjunto dinámico de paises?

Uso del evento Selecting del <asp:LinqDataSource>

En consultas personalizadas podemos implementar un manejador de eventos para el evento “Selecting” en el control

<asp:LinqDataSource>. Con este manejador podemos escribir el código que queramos para obtener los datos. Esto lo

Page 103: Usando Linq to SQL

podemos hacer con una expresión LINQ to SQL, o llamar a unprocedimiento almacenado   o usar una expresión SQL

personalizada. Una vez que obtenemos la secuencia de datos, todo lo que tenemos que hacer es asignar la propiedad

“Result” al objeto LinqDataSourceSelectEventArgs. El <asp:LinqDataSource> usará esta secuencia como los datos con

los que trabajará.

Por ejemplo, aquí tenéis una consulta LINQ to SQL que obtiene aquellos productos de los proveedores de un conjunto

de países:

VB:

C#:

Nota: No tenemos que escribir la consulta en el código del manejador. Una solución más

limpia sería encapsularla en un método de ayuda al que podríamos llamar desde el

propio manejador. Esto lo vimos en laparte 8 de esta serie (usando el método

GetProductsByCategory).

Ahora, cuando ejecutemos la página usando este manejador, sólo obtendremos los productos de los proveedores de

ciertos países:

Page 104: Usando Linq to SQL

Una de las cosas más interesantes es que la paginación y la ordenación siguen funcionando en nuestro GridView –

aunque estemos usando el evento Selecting. Esta lógica de paginación y ordenación ocurre en la base de datos – es

decir, sólo devolvemos los 10 productos de la base de datos que necesitamos para el índice actual del GridView

(supereficiente).

Os estaréis preguntando – ¿cómo es posible que tengamos una paginación y ordenación eficiente incluso cuando lo

hacemos con un evento personalizado?. La razón es que LINQ usa el modelo de ejecución en diferido – es decir, la

consulta no se ejecuta hasta que intentamos iterar sobre los resultados. Uno de los beneficios de este modelo es que

nos permite componer consultas con otras consultas, y añadirles “comportamiento”. Podéis leer más sobre esto en la

tercera parte de la serie LINQ to SQL.

En nuestro evento “Selecting” estamos declarando una consulta LINQ personalizada que queremos ejecutar y luego se

la asignamos a la propiedad “e.Result”. Pero aún no la hemos ejecutado (ya que no hemos iterado sobre los resultados

o llamado a los métodos ToArray() o ToList()). El LINQDataSource es capaz de añadir automáticamente los operadores

Skip() y Take() al aconsulta, así como aplicarle una expresión “orderby” — siendo todos estos valores calculados

automáticamente a partir del índice de página y las preferencias de ordenación del GridView. Sólo entonces el

Page 105: Usando Linq to SQL

LINQDataSource ejecuta la expresión LINQ y obtiene los datos. LINQ to SQL se encarga de que la lógica de ordenación

y paginado se haga en la base de datos – y que sólo se devuelvan 10 filas de productos.

Fijáos cómo podemos seguir usando el GridView para editar y borrar datos, incluso cuando usamos el evento

“Selecting” del LINQDataSource:

El soporte de edicion/borrado funcionará mientras que el evento Selecting asigne la secuencia de resultados a la

propiedad Result y sean objetos entidad (por ejemplo: una secuencia de Product, Supplier, Category, Order, etc). El

LinqDataSource administrará los casos en el que los controles hagan actualizaciones sobre ellos.

Para leer mas sobre cómo funcionan las actualizaciones con LINQ to SQL, leed laparte cuatro de esta serie,  y luego

la parte quinta   para ver las Updates en accción.

Realizano proyecciones de consultas personalizadas con el evento Selecting.

Una de las características más poderosas de LINQ es la habilidad de “formar” o “proyectar” datos. Podemos hacer esto

en una expresión LINQ to SQL para indicar que queremos obtener sólo un subconjunto de valores de una entidad, y/o

Page 106: Usando Linq to SQL

calcular nuevos valores dinámicamente al vuelo con expresiones personalizadas que definamos. Para leer más sobre

esto leed la tercera parte de la serie.

Por ejemplo, podemos modificar el evento “Selecting” para calcular un GridView para que muestre un subconjunto de

información de Product. En el grid queremo mostrar el ProductID, ProductName, Product UnitPrice, el número de

pedidos de ese producto, y el total de pedidos de ese producto. Podemos calcular estos dos últimos campos con la

siguiente expresión LINQ:

VB:

C#:

Nota: El método Sum para calcular el Revenue es un ejemplo de unmétodo de extensión. La

función es una expresión lambda. El tipo de resultados creados de la consulta LINQ es un tipo

anónimo   - ya que el tipo es inferido de la consulta. Métodos de extensión, expresiones

Lambda, y los tipos anónimos son nuevas características de VB y C# en VS 2008.

El resultado de esta expresión LINQ cuando lo enlazamos al GridView es el siguiente:

Page 107: Usando Linq to SQL

Fijaos que la paginación y la ordenación sigue funcionando en el GridView – aunque estemos usando una proyección

de LINQ para los datos.

Una característica que no funcionará con las proyecciones es el soporte para la edición. Esto es debido a que

estamos haciendo una proyección personalizada en el método Selecting, y el LINQDataSource no tiene forma de saber

cómo actualizar la entidad. Si queremos añadir soporte para la edición en este caso, tendremos que crear un control

ObjectDataSource (al que le pondremos un método Update personalizado para contorlarlos), o hacer que el usuario

navegue a una nueva página para hacer la actualización – y mostrar un DetailsView o FormView enlazado a la entidad

Producto para la edición (y no intentar hacerlo en el grid).

Resumen

Podemos realizar consultas personalizadas sobre el modelo LINQ to SQL usando el soporte integrado de filtrado del

LINQDataSource.

Para habilitar opiciones de filtrado más avanzadas, usaremos el método Selecting del LINQDataSource. Esto no

permitirá crear la lógica que queramos para obtener y filtrar datos LINQ to SQL. Podemos llamar a métodos para

obtener los datos, usar Expresiones LINQ, llamar a procedimientos almacenados  o invocar una expresión SQL

personalizada para hacer esto.