Documenti di Didattica
Documenti di Professioni
Documenti di Cultura
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:
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.
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”:
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.
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.
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:
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”.
C#:
VB:
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.
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.
C#:
El código siguiente muestra cómo borrar todos los productos Toy de la base de
datos:
C#:
VB:
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:
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.
Espero que esta introducción os haya abierto el apetito de aprender más. En las
próximas semanas continuaré esta serie de post explorando el LINQ to SQL en más
detalle.
30-mayo-2007
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 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.
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.
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.
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:
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).
Relaciones
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).
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:
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.
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.
30-junio-2007
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:
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.
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:
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:
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 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).
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.
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:
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
Luego, podemos enlazar los resultados de la consulta LINQ to SQL que escribimos
antes:
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:
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.
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:
En el próximo post de esta serie sobre LINQ to SQL veremos cómo podemos añadir
lógica de validación a nuestro modelo de clases de datos, y mostraremos cómo
podemos usarlo para encapsular la lógica de negocio que se ejecutará con cada
actualización, inserción o borrado de nuestros datos. Veremos casos más
avanzados, cómo usar el nuevo control <asp:LINQDataSource> para añadir enlaces
de datos declarativos a controles ASP.NET, resolución de errores de concurrencia
optimista, y más.
13-julio-2007
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.
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.
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:
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.
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:
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:
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.
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
Borrando productos
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”:
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:
Como vemos, el modelo de programación que hemos usado para hacer todo esto es
realmente limpio y orientado a objetos.
Transacciones
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.
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.
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).
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.
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:
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”).
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:
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.
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 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.
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.
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.
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.
En estos post hemos visto cómo podemos usar LINQ to SQL programáticamente
para consultar y actualizar nuestra base de datos.
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:
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>
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”:
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.
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):
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
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:
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:
El grid tiene muchas columnas, y dos de ellas (el SupplierId y el CategoryID) son
claves ajenas, que no conviene mostrar al usuario.
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.
Y ahora, cuando el usuario haga clic en el botón de edición, se mostrará una lista
con todos los proveedores disponibles:
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).
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.
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.
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.
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:
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
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:
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.
27-abril-2008
Parte 8: Crear la versión de escritorio con WPF
Publicado en Scott Guthrië, Silverlight, Wpf a 2:41 pm por Juanma
Este es el último de los ocho tutoriales en el que estamos creando un cliente de
Digg con la Beta 1 de Silverlight 2. La idea es que estos tutoriales se lean en orden,
con el objetivo de explicar los fundamentos de la programación con Silverlight.
Podéis descargar el código completo del cliente Digg del ejemplo aquí
El objetivo con este último tutorial es un poco diferente del de los otros siete. No
vamos a usar Silverlight en este post – sino que usaremos WPF y .NET 3.5.
Cojeremos el código de la aplicación que estamos creando con Silverlight y lo
reutilizaremos como una aplicación de escritorio.
Silverlight viene con un subconjunto compatible de la API del .NET Framework. Uno
de los objetivos de esto es permitir a los desarrolladores aprender un mismo
modelo de programación que les permita reusar código y contenido rico, tanto para
la web como para aplicaciones escritorio.
Aquí tenéis los pasos que he hecho para convertir la aplicación Silverlight que
hemos creado (que se ejecuta en un navegador) en una aplicación de escritorio
Windows (que no se ejecuta en el navegador).
He tenido que hacer dos cambios para que nuestro código compile:
Una vez que hemos hecho estos cambios, el código se compila sin ningún
problema.
Luego añadí nuestro user control Page.xaml del proyecto de Silverlight como el
control raíz de la ventana. Esto hará que sea visible y que se cargue cuando se
cargue la ventana. No tengo que cambiar ningún código de la clase Page ni
renombrar nada. Como hereda de la clase UserControl puede hostearse dentro de
cualquier ventana o control WPF.
Lo último que he tenido que cambiar una cosilla debido a que el servidor de la api
de Digg detecta cuando un cliente no es un navegador y algunas veces le deniega
el acceso (probablemente para evitar scripts automáticos accedan a su servicio).
Esto lo resolví a través de una url de proxy (sin cambiar código, sólo un cambio de
url).
Resumen