18
LINQ to SQL (5ª Parte) – Enlazar controles de interfaz de usuario con el ASP:LinqDatSource 23 respuestas 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 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:

Linq to sql 5

  • Upload
    jcfarit

  • View
    96

  • Download
    2

Embed Size (px)

DESCRIPTION

Ejemplo de consultas en Linq to Sql Parte5

Citation preview

Page 1: Linq to sql 5

LINQ to SQL (5ª Parte) – Enlazar controles de interfaz

de usuario con el ASP:LinqDatSource

23 respuestas

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

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:

Page 2: Linq to sql 5

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

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 el patró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

Page 3: Linq to sql 5

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:

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 4: Linq to sql 5

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:

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.

Page 5: Linq to sql 5

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 6: Linq to sql 5

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:

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

Page 7: Linq to sql 5

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 8: Linq to sql 5

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 9: Linq to sql 5

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:

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

Page 10: Linq to sql 5

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.

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 11: Linq to sql 5

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 12: Linq to sql 5

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:

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

Page 13: Linq to sql 5

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).

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 14: Linq to sql 5

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:

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

Page 15: Linq to sql 5

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 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.

Page 16: Linq to sql 5

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

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 17: Linq to sql 5

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 18: Linq to sql 5

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).

En próximos post veremos en profundidad algunos escenarios con concurrencia optimista, carga a petición, herencia de

mapeado de tablas, y el uso de procedimientos almacenados y SQL personalizados.

La próxima semana tengo pensado empezar otra serie de post sobre el control <asp:ListView> - es un nuevo control de

ASP.NET en la versión .NET 3.5. Nos permite un contorl total sobre el código generado para escenarios de datos (sin

tablas, sin spans, ni estilos en linea ...), también veremos el soporte para paginación, ordenado, edición e inserciones.

Por ejemplo, podemos usarlo en lugar del Grid con un look and feel totalmente personalizado. Lo mejor de todo,

podemos cambiar el código de la página anterior sin tener que cambiar nada del modelo de datos, la declaración del

<asp:linqdatasource>, o el code-behind del trato de errores.