You are on page 1of 112

Usando LINQ to SQL (1 Parte)

En los ltimos meses he escrito una serie de post que cubran algunas de las caracterstcias que van a venir con Visual Studio y .NET Framework Orcas. Aqu tenis los enlaces:

Propiedades automticas, inicializadores de objectos e inicializadores de colleciones. Mtodos de extensin. Expresiones Lambda. Sintaxis de consultas. Tipos Annimos

Las caractersticas anteriores hacen que la consulta de datos sea un concepto de primera clase. Conocemos a este modelo de programacin 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 programacin que eligan, opcionalmente transformar/incrustar los resultados de las consultas en el formato que quieran, y entonces manipular fcilmente los resultados. Los lenguajes habilitados para LINQ pueden aportar seguridad de tipos y chequeo en tiempo de compilacin el las expresiones de consulta, y desarrollar herramientas que aporten intelisense, debugging, y un gran soporte para refactoring cuando escriban cdigo de LINQ. LINQ soporta un modelo de extensibilidad muy rico que facilita la creacin de operadores eficientes para fuentes de datos. La versin Orcas del .NET Framework biene con libreras que habilitan LINQ sobre objetos, XML y bases de datos. Qu es LINQ to SQL? LINQ to SQL es una implementacin de O/RM(object relational mapping, mapeador de objetos relacionales) que viene con la versin 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/aadir/borrar datos de ellas. Modelando bases de datos con LINQ to SQL: Visual Studio Orcas viene con un diseador de LINQ to SQL que nos aporta una forma fcil de modelar y visualizar una base de datos como un modelo de objeto de LINQ to SQL. El prximo post cubrir en ms profundidad cmo usar este diseador (podis ver ste video que hice en Enero para verme construir un modelo LINQ to SQL). Usando ese diseador LINQ to SQL puedo crear fcilmente una representacin de la base de datos Northwind:

El diseo 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 tpicamente modeladas como relaciones primary-key/foreign-key en la base de datos. La direccin de las flechas en el diseador indican si la relacin es uno-a-uno o uno-a-varios. Se aadiran propiedades fuertemente tipadas a las entidades basndose en esto. Por ejemplo, la clase Category de arriba tiene una relacin de uno-a-varios con la clase Product. Esto implica que tendr una propiedad Categories que es una coleccin de objetos Product con esa categora. La clase Product entonces tiene una propiedad Category que apunta a una instancia de la clase Category representando la categora a la que pertenece el producto. El panel de la derecha del diseador LINQ to SQL contiene una lista de procedimientos almacenados que interactan con nuestro modelo de base de datos. En el ejemplo de arriba hemos aadido un SPROC (Procedimiento almacenado)

GetProductsByCategory. Como entrada recibe un categoryID, y devuelve una secuencia de Product como resultado. Veremos cmo llamar a este procedimiento almacenado en un ejemplo. Entendiendo la clase DataContext Cuando pulsis el boton save del diseador 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 aadido a nuestra solucin por el diseador LINQ to SQL tambin 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 representarn a cada tabla que hemos modelado, as como mtodos para cada procedimiento almacenado que aadamos. Por ejemplo, aqu tenis la clase NorthwindDataContext:

Ejemplos de LINQ to SQL Una vez que hemos modelado nuestra base de datos con el diseador de LINQ to SQL, podemos escribir cdigo fcilmente para trabajar con l. Aqu tenis unos cuantos ejemplos que muestran tareas comunes con datos: 1) Consultando Products de la base de datos

El siguiente cdigo usa una consulta LINQ para obtener una secuencia IEnumerable de objetos Product. Fijos que este cdigo est consultando a traves de la relacin Product/Category para obtener aquellos productos de la categora Beverages. C#:

VB:

2) Actualizando un producto en la base de datos. El cdigo siguiente muestra cmo 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 an. Pero en la Beta2 s -de forma que el cdigo anterior se podr escribir de una forma ms concisa. 3) Aadir una nueva categora y dos nuevos productos en la base de datos. El siguiente cdigo muestra cmo crear una nueva categora, y entonces crear dos nuevos productos y asociarlos a la nueva categora. Los tres son despus guardados en la base de datos. Fijaos como no necesitamos administrar manualmente las relaciones primarykey/foreignkey. Slo tenemos que aadir los objetos Product en la coleccin Products de la categora, y luego aadir el nuevo objeto Category en la coleccin de Categories del DataContext, LINQ to SQL sabr automticamente crear las PF/FK necesarias: C#:

4)Borar productos de la base de datos. El cdigo siguiente muestra cmo borrar todos los productos Toy de la base de datos:

C#:

VB:

5) Llamar a un procedimiento almacenado. El cdigo siguiente muestra cmo obtener entidades de la tabla Product sin usar una consulta LINQ, sino llamando al procedimiento almacenado GetProductsByCategory que aadimos a nuestro modelo de datos. Fijos 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:

6) Obtener productos con paginado del lado del servidor El cdigo siguiente muestra cmo implementar un paginado eficiente en el lado servidor como parte de una consulta LINQ. Usando los operadores Skip() y Take(), slo devoleremos 10 filas de la base de datos a partir de la fila 200. C#:

VB:

Resmen: 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 fcil y eficiente.

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 aqul post pusimos unos cuantos ejemplos de cdigo donde demostrbamos cmo mejorar la parte de datos usando LINQ to SQL: Cmo consultar una base de datos. Cmo actualizar filas en una base de datos Cmo aadir y relacionar varias filas en una base de datos. Cmo eliminar filas de la base de datos. Cmo llamar a procedimientos almacenados. Cmo obtener datos con paginacin en el servidor.

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

En este segundo post de la serie vamos a ver en ms detalle cmo crear el modelo anterior con LINQ to SQL. LINQ to SQL, el diseador de LINQ to SQL, y todas las caractersticas que estamos viendo saldrn con la versin de .NET 3.5 y en la release de Visual Studio Orcas. Podis seguir todos los pasos siguientes descargndo tanto Visual Studio Orcas Beta 1 o Visual Web Developer Express Orcas Beta 1. Podis instalar las dos y usarlas sin ningn problema con Visual Studio 2005. Crear un nuevo modelo de datos LINQ to SQL Podemos aadir un modelo de datos de LINQ to SQL a un projecto ASP.NET, Class Library o Windows, con la nueva opcin Add New Item seleccionando LINQ to SQL:

Seleccionando LINQ to SQL lanzar el diseador de LINQ to SQL, y nos permitir modelar las clases que representen una base de datos relacional. Tambin crear una clas fuertemente tipada DataContext que tendr las propiedades que representarn cualquier tabla que modelemos de la base de datos, as como mtodos 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 tenis una captura de pantalla de un diseo LINQ to SQL ORM vaco, es lo que veris despues de crear un nuevo modelo de datos LINQ to SQL:

Clases Entidad (Entity) LINQ to SQL nos permite modelar clases que mapeen una base de datos. Estas clases son tpicamente 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 especfica, lo que significa que pueden heredar de cualquier objeto que queramos. Todas las clases creadas por el diseador de LINQ to SQL se definen como clases parciales con lo que podemos, opcionalmente, aadir propiedades adicionales, mtodos y eventos. A diferencia de la caracterstica de DataSet/TableAdapter que aporta VS 2005, cuando usamos el diseador 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, cmo se mapean con la base de datos, y las relaciones entre ellas. La implementacin del ORM de LINQ to SQL se encargar de generar la lgica de ejecucin SQL por nosotros en tiempo de ejecucin para que podamos interactuar y usar las entitades de datos. Podemos usar sintaxis de consultas LINQ para indicar cmo 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.

La forma ms 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 diseador LINQ to SQL:

Cuando aadimos estas dos tablas (Categories y Products) y una vista (Invoices) de la base de datos Northwind al diseador 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 cdigo (excepto el de procedimientos almacenados) que vimos en la primera parte de esta serie sobre LINQ to SQL. No tenemos que aadir ningn cdigo adicional o configuracin para habilitar los escenarios de consulta, insercin, actualizacin, borrado, y paginacin en el servidor. Nombrado y pluralizacin Una de las cosas de las que os daris cuenta usanto el diseador de LINQ to SQL es que automticamente pluraliza los nombres de las tablas y columnas cuando crea las clases entidad basdas 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 ms consistente con las convenciones de nomenclatura de .NET, y encuentro bastante til que el diseador haga esto por mi (especialmente cuando aadimos muchas tablas a nuestro modelo). Si no os gusta el nombre de una clase o propiedad que el diseador ha generado, siempre podris cambiarlo por el que queris. Podis hacerlo editanto el nombre de la entidad/propiedad en el mismo diseador o cambiarlo en la rejilla de propiedades:

Esta habilidad de nombrado de entidades/propiedades/asociaciones es muy til en un gran nmero de casos. En particular: 1) Cuando cambie el nombre de una tabla/columna de vuestra base de datos. Como vuestras entidades tendrn nombres diferentes, podis decidir actualizar las reglas de mapeado y no el cdigo de vuestra aplicacin 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, podis 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 diseador LINQ to SQL, Visual Studio comprobar las relaciones de clave primaria y ajenas de los objetos, y basndose en ellas crear relaciones por defecto entre las diferentes clases entidad que genere. Por ejemplo, cuando aadimos las tablas Products y Categories de la base de datos NorthWind al diseador LINQ to SQL podemos ver que se ha deducido una relacin de uno a n entre ellas (esto se indica con la felcha del navegador):

Esta relacin har que la clase entidad Product tenga una propiedad llamada Category que los desarrolladores usarn para acceder a la entidad Category para un Product dado. Tambin har que la clase Category tenga una coleccin de Products que permitir a los desarrolladores obtener todos los productos de una Category.

Si no nos gusta cmo el diseador a nombrado a la relacin, siempre podrmos cambiarlo. Slo hay que hacer clic en la felcha en el diseador, 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 asociacin en el diseador, 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 categora, y slo queremos esa imagen cuando vaya a usarla (y no cuando est haciendo una consulta para obtener los nombres de las categoras en una lista). Podramos configurar la propiedad Picture para que se retrase su carga seleccionandola en el diseador de LINQ to SQL y en las propiedades poner Delay Loaded a true:

Nota: Adems de configurar el significado de la precarga/retraso de las entidades, podemos sobreescribirlo va cdigo 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 mtodos de nuestra clase DataContext. Por ejemplo, supongamos que hemos definido un procedimiento almacenado simple para obtener la informacin de un producto de un categoryID:

Podemos usar el server explorer de Visual Studio y arrastrar este procedimiento almacenado al diseador de LINQ to SQL para obtener un mtodo fuertemente tipado que invocar a este procedimiento almacenado. Si lo arrastramos encima de la entidad Product en el diseador, el diseador declarar que el procedimiento almacenado devuelve un IEnumerable<Product>:

Podemos usar tanto una consulta SQL (que generar una consulta SQL adhoc) o invocar el procedimiento almacenado aadido para obtener las entidades product de la base de datos:

Usar procedimientos almacenados para actualizar/borrar/insertar datos. Por defecto LINQ to SQL crear automticamente expresiones SQL apropiadas para cuando tengamos que insertar/actualizar/borrar entidades. Por ejemplo, si escribimos el siguiente cdigo 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 ms profundidad en otros post).

Podemos definir procedimientos almacenados personalizados para INSERT, UPDATE, DELETE. Para configurar esto, hacemos clic en una entidad del diseador LINQ to SQL y en las propiedades de Delete/Insert/Update, en el botn , 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 actualizacin del cdigo que vimos ntes sigue funcionando sin tener que hacer ninguna modificacin. Con esto libramos a los desarrolladores de que si cambiamos el modelo de datos LINQ to SQL, no tienen que tocar ningn cdigo para que sigua funcionando si deciden poner un procedimiento almacenado personalizado. 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 diseador 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 rpido. El diseador LINQ to SQL tambin 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 prximos post usaremos este modelo que hemos creado para ver en ms detalle los procesos de consulta, inserciones, actualizaciones y borrados. En estos post tambin veremos cmo aadir validaciones negocio/datos personalizadas a las entidades que hemos diseado.

Mike Taulty tiene una gran cantidad de videos sobre LINQ to SQL aqu, os recomiendo que los veis. As tenis una forma de aprender viendo cmo 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 tenis 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 ms detalle cmo usar el modelo de datos que creamos en la segunda parte, y veremos cmo 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 cmo crear un modelo de clases LINQ to SQL usando el diseador de LINQ to SQL que viene con VS 2008. Aqu tenis 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 fcilmente datos de nuestra base de datos. LINQ to SQL nos permite esto usando la sintxis de consultas de LINQ sobre la clase NorthwindDataContext que creamos con el diseador LINQ to SQL. Por ejemplo, para obtener e iterar sobre una secuencia de objetos Product podemos escribir el siguiente cdigo:

En esta consulta hemos usado la sentencia where en nuestra consulta LINQ para devolver aquellos productos de una categora. 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 cmo consultar nuestros datos, y podemos aprovecharnos de las asociaciones que hicimos cuando modelamos las clases de LINQ to SQL para hacer consultas ms 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:

Fijos en cmo estamos usando la propiedad Category de cada objeto Product para filtrarlos por CategoryName. Esta propiedad fue creada automticamente por LINQ to SQL ya que modelamos las clases Category y Product con una relacin varios a uno en la base de datos. Por poner otro ejemplo del uso de las relaciones de nuestro modelo, podramos escribir la siguiente consulta LINQ para obtener aquellos productos que tengan ms de cinco rdenes para ellos:

Fijos cmo usamos la coleccin OrderDetails que LINQ to SQL cre en cada clase Product (debido a la relacin 1 a varios que modelamos en el diseador LINQ to SQL). Visualizando consultas LINQ to SQL en el debugger Los ORM como LINQ to SQL administran automticamente la creacin y la ejecucin del cdigo 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 cdigo SQL se est ejecutando? Una de las cosas que hace LINQ to SQL es poder ver exctamente qu cdigo SQL se est ejecutando cuando ejecutamos nuestra aplicacin con el debugger. Con la beta 2 de VS 2008 podemos usar el nuevo plug-in de visualizacin LINQ to SQL para ver (y testear) cualquier consulta LINQ to SQL. Simplemente aadimos un breakpoint y pasamos el ratn por encima y hacemos clic en la lupa para visualizar esa consulta:

ESto nos mostrar un cuadro de dilogo que nos dir exactamente la SQL que LINQ to SQL usar cuando se ejecute la consulta para obtener los objetos Product:

Si pulsamos el botn Execute de este dilogo nos permitir evaluar el SQL dentro del debugger y nos mostrar los resultados de la base de datos:

Obviamente esto hace realmente fcil ver qu lgica de consultas SQL est realizando LINQ to SQL. Fijos 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 cdigo 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 pgina .aspx de la siguiente forma:

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

Esto generar una pgina 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:

El resultado de esta consulta es:

Normalmente slo queremos un subconjunto de los datos de cada producto. Podemos usar la nueva caracterstica que LINQ y los compiladores de C# y VB tienen para indicar que slo 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):

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 nmero total de pedidos que hemos hecho de productos, y los suma al total de pedidos de Productos:

La expresin a la derecha de la propiedad Revenue es un ejemplo del uso delmtodo de extensin Sum de LINQ. Toma una expresin Lambda que devuelve el valor de cada pedido de producto como argumento. LINQ to SQL es listo y es capaz de transformar la expresin LINQ anterior al siguiente SQL cuando es evaluado (con el visor del debugger):

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 rpido):

Podemos enlazar el resultado anterior a nuestro gridview:

BTW en caso de que os lo preguntis, tenemos intellisense en VS 2008 cuando escribimos estos tipos de restricciones en las consultas LINQ:

En este ejemplo estamos declarando un tipo annimo que usa la inicializacin de objetos para amoldar y definir la estructura del resultado. Y seguimos teniendo intellisense en VS 2008, chequeo de compilacin y soporte para refactoring con estos tipos anonimos:

Paginando los resultados de la consulta.

Una de las necesidades ms comunes en entornos web es la posibilidad de hacer eficientemente la paginancin en las interfaces de usuario. LINQ tiene dos mtodos de extensin que permite hacer esto de forma fcil y eficiente los mtodos Skip() y Take(). Podemos usar los mtodos Skip() y Take() para indicar que slo queremos devolver 10 objetos producto desde la fila que le pasemos como argumento:

Fijos que no aadimos ni Skipt() ni Take() en la primera consulta sino que lo hacemos despus 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 paginacin (esto es malo)? No. La cuestin es que LINQ usa un modelo de ejecucin en diferido, es decir, la consulta no se ejecuta hasta que se itera sobre los resultados. Uno de los beneficios de este modelo de ejecucin en diferido es que nos permite crear consultas en varias lneas de cdigo (lo que mejora la claridad). Tambin nos permite crear las consultas despus de otras lo que nos permite composiciones ms flexibles y reutilizacin. Una vez que tenemos el mtodo BindProduct(), podemos escribir el siguiente cdigo en nuestra pgina 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 pgina de productos, filtrada para mostrar aquellos productos que tengan ms de cinco pedidos, mostrando datos calculados dinmicamente, y que son paginables a partir de una cadena de consulta:

Nota: Cuando trabajamos contra SQL 2005, LINQ to SQL usar la funcin SQL ROW_NUMBER() para crear toda la lgica de paginacin en la base de datos. Esto nos asegura que slo devolver las 10 filas de datos que queremos mostrar en la pgina:

Esto hace realmente fcil 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 ms sobre expresiones LINQ y las nuevas caractersticas de consultas que traen los compiladores de C# y VB con VS 2008, leed estos post:

Nuevas caractersticas de la nueva versin de C# Orcas Mtodos de extensin. Expresiones Lambda Sintaxis de consultas Tipos annimos

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 versin 3.5 del framework de .NET, y nos permite modelar fcilmente 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 tenis los links a los tres primeros post:

Parte 1: Introduccin a LINQ to SQL Parte 2: Definiendo el modelo de datos. Parte 3: Consultando la base de datos

En el post de hoy veremos cmo usar el modelo de datos que hemos creado, y usarlo para actualizar, insertar y borrar datos. Tambin veremos cmo integrar reglas de negocio y crear lgica de validacin 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 cmo crear el modelo de clases con el diseador de LINQ to SQL que trae VS 2008. Aqu tenis 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 diseador 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 automticamente estas expresiones LINQ al cdigo SQL apropiado en tiempo de ejecucin.

Por ejemplo, la siguiente expresin 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 dlares:

Estamos usando la asociacin OrderDetails de cada producto como parte de la consulta slo 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 sern 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 ningn recurso de la base de datos mientras lo usemos, tampoco tenemos que cambiar/instalar nada en la base de datos para que esto funcione.

Despus de realizar los cambios que queramos a los objetos que hemos obtenido con LINQ to SQL, podemos llamar al mtodo 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 cdigo actualiza el precio y las unidades en stock del producto Chai en la base de datos:

Cuando llamamos al mtodo northwind.SubmitChanges(), LINQ to SQL crear y ejecutar las sentencias UPDATE de SQL necesarias para guardar las propiedades modificadas. Con el siguiente cdigo iteramos sobre los productos menos populares y caros y ponemos la propiedad ReorderLevel a cero.

Cuando llamamos al mtodo 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 asignacin anterior, LINQ to SQL no ejecutar ninguna actualizacin para ese objeto. Por ejemplo si el precio del producto Chai era 2 dolares, y el nmero de unidades en stock era cuatro, la llamada a SubmitChanges() no actualizara esos valores. Slo los productos cuyo ReorderLevel no era 0 se actualizarn. Ejemplos de insercin y borrado Adems de poder actualizar la base de datos, LINQ to SQL tambin nos permite insertar y eliminar datos. Esto lo conseguimos aadiendo o eliminando objectos de las colecciones disponibles en DataContest, y luego llamar al mtodo SubmitChanges(). LINQ to SQL monitorizar esas inserciones y borrados, y generar el cdigo SQL necesario cuando se invoque a SubmitChanges() Aadiendo un producto

Podemos aadir un producto a la base de datos creando un nuevo objeto Product, inicializando sus propiedades y aadirlo a la coleccin Products de nuestro DataContext:

Cuando llamemos a SubmitChanges() se aadir una nueva fila en la tabla de productos. Borrando productos De la misma forma que aadimos un nuevo producto a la base de datos aadiendo un objeto Product a la coleccin Products del DataContext, tambin podemos borrar productos borrndolos de esa misma coleccin:

Lo que estamos haciendo es obtener una secuencia de productos alternados de la tabla, es decir, no ordenados por ninguna expresin LINQ, y luego esa secuencia se la pasamos al mtodo RemoveAll() de la coleccin Products. Cuando llamamos a SubmitChanges() todos esos productos sern borrados de la tabla Actualizaciones y relaciones Lo que hace que los O/RMs como LINQ to SQL sean tan flexibles es que tambin nos permiten modelar las relaciones entre las tablas. Por ejemplo, podemos modelar que cada producto tenga una categora, 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 cmo 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 cdigo creamos un nuevo producto y lo asociamos con la categora Beverages:

Estamos aadiendo el objeto producto en la coleccin de categoras de productos. Esto indicar que hay una relacin entre dos objetos, y har que LINQ to SQL mantenga automticamente las relaciones de clave primaria/ajena entre los dos cuando llamemos a SubmitChanges(). Veamos otro ejemplo para ver cmo LINQ to SQL nos ayuda a mantener limpio el cdigo referente a las relaciones entre las tablas. En el siguiente ejemplo estamos creando un nuevo pedido para un cliente existente. Despus 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 programacin que hemos usado para hacer todo esto es realmente limpio y orientado a objetos. Transacciones Una transaccin es un servicio de la base de datos que garantiza que un conjunto de acciones individuales van a suceder de forma atmica es decir, o se pueden completar todas o si hay alguna que falle, todas las demas se descartarn, y el estado de la base de datos ser el mismo que ntes de comenzar la transaccin. Cuando llamemos a SubmitChanges(), las actualizaciones se mapean en una nica transaccin. 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 transaccin en curso, el objeto DataContext empezar una transaccin de la base de datos para guardar las actualizaciones que hagamos con SubmitChanges(). Pero LINQ to SQL tambin nos permite definir explcitamente y usar nuestro propio sistema de transacciones (introducido en la versin 2.0 de .NET). Esto hace ms fcil an integrar cdigo LINQ to SQL con el cdigo de acceso a datos que ya tengamos. Tambin nos permite encolar recursos que no son propios de la base de datos en la misma transaccin - 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 transaccin a la hora de actualizar la base de datos Validacin y lgica de negocio Una de las cosas ms importantes que los desarrolladores tienen que hacer cuando trabajan con datos es incorporar validacin y reglas de negocio. LINQ to SQL tiene varias formas para hacer que los desarrolladores puedan hacer eso de forma fcil y clara. LINQ to SQL nos permite aadir esta validacin lgica una vez. De forma que no tendremos que repetir esa lgica en varios sitios, con lo que conseguimos un modelo de datos ms mantenible y ms claro. Soporte de validacin de esquemas Cuando definimos el modelo de clases de datos con el diseador de LINQ to SQL de VS 2008, se aadirn algunas reglas de validacin 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 coincidirn con el esquema de la base de datos. Con esto tendremos errores de compilacin si intentamos asignar un booleano a un valor decimal, o si convertirmos tipos numricos incorrectamente. Si una columna en la base de datos est marcada como nullable, la propiedad correspondiente que crea el diseador de LINQ to SQL ser un tipo nullable. Las columnas marcadas como no nullables lanzarn excepciones si no les

asignamos ningun valor. LINQ to SQL tambin se asegurar que de que los valores identidad/unicos se asignan correctamente. Obviamente podemos usar el diseador LINQ to SQL para sobreescribir los valores por defecto del esquema si queremos pero por defecto, las tendremos automticamente sin tener que hacer nada. LINQ to SQL tambin comprueba los valores de los parmetros de las consultas SQL, de manera que no tendremos que preocuparnos por los ataques de inyeccin de SQL. Soporte para validacin personalizada de propiedades La validacin de datos a travs 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 cdigo para actualizarlo con un nmero de telfono vlido:

El problema que nos encontraramos, sera que el siguiente cdigo sigue siendo vlido desde el punto de vista de un esquema SQL (ya que sigue siendo una cadena, no un nmero de telfono vlido).

Para no permitir que no se puedan meter nmeros de telfono errneos en nuestra base de datos, podemos aadir una regla de validacin personalizada a la clase Customer de nuestro modelo de datos. Es realmente fcil, todo lo que necesitamos hacer es aadir una nueva clase parcial a nuestro proyecto que defina el siguiente mtodo:

Este cdigo usa dos caracteristicas de LINQ to SQL: 1. Todas las clases que genera el diseador LINQ to SQL son parciales es decir, podemos aadir mtodos adicionales, propiedades, y eventos (en archivos separados). As podemos extender nuestro modelo de clases creada por el diseador de LINQ to SQL con reglas de validacin y mtodos auxiliares que definamos. No es necesario ninguna configuracin.

2. LINQ to SQL expone una serie de puntos de extensin en el modelo de datos que podemos usar para aadir
validacin lgica. Muchos de estos puntos de extensin usan la nueva caracterstica llamada mtodos parciales que viene con VB y C# en VS 2008 Beta2. Wes Dyer el equipo de C# ha escrito un post explicando cmo va esto de los mtodos parciales. En nuestro ejemplo de validacin, estamos usando el mtodo parcial OnPhoneChangin que se ejecuta cada vez que se cambia el valor de la propiedad Phone de un objeto Customer. Podemos usar este mtodo para validar la entrada de datos (en este caso estamos usan una expresin regular). Si todo va bien, LINQ to SQL asumir que el valor es vlido. Si hay algn problema con el valor, podemos lanzar una excepcin en el mtodo de validacin que har que la asignacin no se haga. Soporte para validacin personalizada de objetos entidad. En el punto anterior hemos visto cmo aadir validacin 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:

Este cdigo es legal desde el punto de vista de SQL aunque no tenga ningn sentido la propiedad de fecha de entrega, que era para ayer. LINQ to SQL en Beta2 nos permite aadir reglas de validacin a nivel de entidad para corregir este tipo de errores. Podemos aadir una clase parcial para nuestra entidad Order e implementar el mtodo 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 slo lectura a los objetos asociados), y lanzar una excepcin si el valor es incorrecto. Cualquier excepcin lanzada desde el mtodo OnValidate() abortar cualquier cambio que queramos hacer en la base de datos, y deshacer todos los cambios hechos en la transaccin actual. Validacin en los mtodos de insercin/actualizacin/borrado. A menudo necesitamos aadir validacin especfica en los mtodos de insercin, actualizacin o borrado. LINQ to SQL nos lo permite aadiendo una clase parcial que extienda a la clase DataContext e implementar mtodos parciales para personalizar la lgica de insercin, actualizacin y borrado de las entidades de nuestro modelo de datos. Estos mtodos sern llamados automticamente cuando invoquemos a SubmitChanges(). Podemos aadir la validacin lgica que estimemos oportuna con estos mtodos y si todo va bien, LINQ to SQL continar guardando los datos en la base de datos (llamando al mtodo de DataContext ExecuteDynamicXYZ).

Podemos aadir mtodos que se invocarn automticamente 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 mtodo parcial InsertOrder. Avanzado: Viendo la lista de cambios de la transaccin

Hay veces que no nos interesa aadir validacin lgica a elementos individuales, sino que queremos ser capaces de ver toda la lista de cambios que estn ocurriendo en una transaccin. Desde la Beta2 de .NET 3.5, LINQ to SQL nos permite acceder a la lista de cambios a travs del mtodo DataContext.GetChangeList(). Nos devolver un objeto ChangeList que expone una serie de colecciones de adiciones, borrados y modificaciones que se han hecho. Una aproximacin que podemos hacer en algunos escenarios es crear una clase parcial de la clase DataContext y sobreescribir su mtodo SubmitChange(). Podemos obtener la lista de ChangeList() para las operaciones de actualizaciones y crear cualquier validacin 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 caractersticas de LINQ to SQL. Administrando cambios simultneos con concurrencia optimista. Una de las cosas en las que tenemos que pensar los desarrolladores en entornos multi-usuarios es cmo 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 cmo tratar ese conflicto. Una solucin 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 solucin muy pobre (e incorrecta). Otra solucin que permite LINQ to SQL es usar el modelo de concurrencia optimista, es decir, LINQ to SQL detectar automticamente 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 aplicacin para que nos indique el propio usuario lo que quiere hacer. Ya veremos en ms detalle este tema en un prximo post. Uso de procedimientos almacenados o lgica 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 cmo 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 aadir, 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 lgica de aplicacin que estamos usando para nuestro modelo de datos, ni cambiar nada de las validaciones ni de la lgica de negocio. Esto nos da una gran flexibilidad a la hora de construir nuestra aplicacin. Dejaremos para otro post cmo personalizar los modelos de datos con procedimientos almacenados o sentencias SQL. Resumen. Este post presenta un buen resumen sobre cmo podemos usar LINQ to SQL para actualizar nuestra base de datos e integrar de una forma clara validacin de datos y lgica de negocio. Creo que encontraris que LINQ to SQL incrementa mucho la prouctividad a la hora de trabajar con datos, y nos permite escribir cdigo 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 versin 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 tenis los links a los post anteriores:

Parte 1: Introduccin 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 cmo podemos usar LINQ to SQL programticamente para consultar y actualizar nuestra base de datos. En el post de hoy veremos el nuevo control <asp:LinqDataSource> de la nueva versin 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. Aplicacin de ejemplo que construiremos. El ejemplo que veremos se trata de una aplicacin muy simple que nos va a permitir editar los datos de la tabla products:

La aplicacin le da al usuario las siguientes opciones de gestin:

1. 2. 3. 4. 5.

Filtrado de productos por categoras. Ordenar los productos haciendo clic en la cabecera de las columnas (Nombre, Precio, unidades en stock, etc) Navegar en por los productos de 10 en 10. Edicin de los detalles de cualquier producto. Borrar productos de la lista.

La aplicacin 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 lgicas se implementarn en el la capa de datos y no en la capa de presentacin ni en ninguna pgina web. Con esto conseguiremos: 1) Un conjunto consistente de reglas de negocio que sern usadas en toda la aplicacin, 2) escribiremos menos cdigo y mejor an, no lo repetiremos y 3) podremos cambiar las reglas de negocio cuando queramos sin tener que actualizar ese cdigo en miles de sitios en toda la aplicacin. Tambin aprovecharemos el soporte de paginado y ordenacin de LINQ to SQL para asegurarnos que tales operaciones no se realizan en la capa intermedia, sino en la base de datos (es decir, slo obtendremos 10 productos de la base de datos en cada momento no estamos obteniendo miles de filas y ordenndolas/paginndolas en el servidor web). Qu es el control <asp:LinqDataSource> y cmo nos ayuda? El control <asp:LinqDataSource> es un control de ASP.NET que implementa elpatrn 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 pgina 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 genrica (como el ObjectDataSource), este control est diseado 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 mtodos para insercin/consulta/actualizacin y borrado para el datasource sino que aadimos 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 bsico de los productos que use las entidades Product con un modelo de datos LINQ to SQL, slo tenemos que declarar un control <asp:linqdatasource> en nuestra pgina 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 ms, podemos ejecutar la pgina y tener un listado de los productos con paginado y ordenacin. Podemos aadir los botones edit y delete en el grid y tener soporte automtico para ello. No tenemos que aadir ningn mtodo, mapear ningn parmetro, ni escribir ningn cdigo 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 validacin que hemos aadido se cumplan ntes de guardar los datos.

Importante: La belleza de LINQ y LINQ to SQL es que obviamente no slo 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 cdigo con este ORM es muy limpio. Siempre podemos escribir cdigo 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 aplicacin 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 cmo definirlo en la segunda parte de estos artculos. Aqu tenis una captura de pantalla de las clases del modelo de datos creado con el diseador de LINQ to SQL de la base de datos Northwind:

Volveremos sobre nuestro modelo de datos en el paso 5 de este tutorial cuando aadamos algunas reglas de validacin de negocio. Pero para empezar usaremos el modelo de arriba. Paso 2: Creacin de un listado bsico de productos. Empezaremos a crear la interfaz con una pgina ASP.NET con un control <asp:gridview> con algun estilo css:

Podramos escribir cdigo para enlazar programticamente 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) grficamente a datos LINQ. Para hacerlo tenemos que pasar a la vista de diseo, seleccionar el GridView y elegir la opcin New Data Source en Choose Data Source:

Esto nos mostrar un cuadro de dilogo con una lista de fuentes de datos disponibles. Seleccionamos la nueva opcin LINQ y le damos el nombre que queramos:

El diseador del control <asp:linqdatasource> nos mostrar las clases DataContext de LINQ to SQL que hay disponibles (incluyendo aquellas que estn en las libreras que tengamos referenciadas):

Seleccionaremos el modelo que creamos con el diseador 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. Tambin seleccionamos el boton Advanced y habilitaremos las actualizaciones y borrados para la fuente de datos:

Cuando hagamos clic en el botn Finish, VS 2008 declarar un contorl <asp:linqdatasource> en el .aspx y actualizar el gridview para que use esta fuente de datos. Tambin 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 paginacin, ordenado, edicin y borrado:

Podemos pular F5 para ejecutar la aplicacin, y veremos una pgina con el listado de productos con paginacin y ordenado:

Tambin podemos pulsar los botones edit o delete en cada fila para actualizar los datos:

Si pasamos a la vista de cdigo de la pgina, 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, cul es el texto de la cabecera, y cual es la expresin de ordenacin:

Ahora tenemos lo bsico 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 cdigo(borrando la declaracin de <asp:boundfield> correspondiente) o en la vista de diseo (haciendo clic en la columna y seleccionando la tarea remove). Por ejemplo, podemos eliminar la columna QuantityPerUnit y ejectuar la aplicacin:

Si hemos usado el contorl <asp:ObjectDataSource> y le hemos indicado explcitamente los parmetros de actualizacin (update) a los mtodos de actualizacin (por defecto cuando usamos un DataSet basado en TableAdapters) una de las cosas que tenemos que hacer es cambiar la firma de los mtodos de actualizacin del TableAdapter. Por ejemplo: si eliminamos una columnan del grid, tenemos que modificar el TableAdapter para que soporte los mtodos de actualizacin sin parmetros. Con el control <asp:LinqDataSource> es que no tendramos que hacer este tipo de cambios. Simplemente borrando (o aadiendo) una columna a la interfaz de usuario y ejecutamos la aplicacin -no hacen falta ms cambios. Con esto conseguimos que los cambios que se hagan en la interfaz de usuario sean mucho ms fciles, y nos permite iteraciones ms rpidas en nuestra aplicacin. 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 categora y el nombre del proveedor, y mostrar una lista desplegable en modo edicin para que podamos cambiar estas asociaciones de forma fcil. Podemos cambiar el gridview para que muestre el nombre del proveedor y el de la categora en lugar del ID, cambiando el <asp:BoundField> por un <asp:TemplateField>. Y en este templateField aadimos el contenido que queramos para personalizar la vista de la columna. En el cdigo siguiente aprovecharemos la capacidad de LINQ to SQL, que model este campo como una propiedad. Es decir, posdemos enlazar de forma fcil las propiedades Supplier.CompanyName y Category.CategoryName al grid:

Ahora ejecutamos la aplicacin y tenedremos los valores de Category y Supplier de la siguiente forma:

Para tener una lista desplegable en estos dos campos en el modo edicin, tenemos que aadir dos controles <asp:LinqDataSource> a la pgina. 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 aadimos antes y personalizaremos la parte de edicin (especificando un EditItemTemplate). De forma que tendremos una lista desplegable en la vista edicin, donde los valores disponibles se obtendrn de las fuentes de datos de categoras y proveedores, y enlazaremos doblemente el valor seleccionado al SupplierId y CategoryID de las claves ajenas:

Y ahora, cuando el usuario haga clic en el botn de edicin, 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. Ms 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 categora particular. Como ya aadimos un <asp:LinqDataSource> enlazada a las Categoras de nuesto modelo de LINQ to SQL, slo tendremos que crear un nuevo control de lista desplegable y enlazarlo. Por ejemplo:

Cuando ejecutemos la pgina tendremos un filtro con todas las categoras al principio de la pgina:

Lo ltimo que queda es que cuando seleccionemos una categora se muestren los productos de dicha categora en el gridview. Lo ms facil es seleccionar la opcin 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 botn Where para aadir un campo de filtro al datasource. Podemos aadir cualquier nmero 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 pgina, 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:

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

Y cuando ejecutamos la aplicacin el usuario ser capaz de elegir una categora en la lista de filtrado y paginar, ordenar, editar y borrar los productos de una categora:

El control <asp:LinqDataSource> aplicar las expresiones LINQ necesarias para que cuando se ejecute contra el modelo de datos LINQ to SQL slo se obtengan los datos necesarios de la base de datos (por ejemplo: en el grid anterior slo obtendremos 3 filas con los productos de la categora Confection). Tambin podemos gestionar nosotros el evento Selecting si queremos escribir expresiones LINQ personalizadas. Paso 5: Aadir reglas de validacin 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 validacin 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 bsico de validacin es slo el primer paso, y es muy raro en la mayora de aplicaciones reales. Normalmente necesitaremos aadir reglas adicionales a nuestro modelo de datos. Afortunadamente con LINQ to SQL podemos aadir estas reglas de forma muy fcil (para ms detalles sobre este tema, leed la cuarta parte de esta serie de post). Ejemplo de escenario con reglas de validacin Por ejemplo, supongamos una regla bsica que queramos reforzar. Queremos que un usuario de nuestra aplicacin 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. Aadiendo una regla de validacin al modelo de datos. El sitio incorrecto para aadir este tipo de validacin es en la capa de presentacin. Aadirlo en esta capa implica que esta regla ser slo vlida en un lugar concreto, y no ser automtico en cualquier parte de la aplicacin. Distribuir la lgica de negocio en la capa de presentacin tambin har que nuestra vida sea realmente penosa a medida que nuestra aplicacin crezca ya que cualquier cambio/actualizacin en nuestro negocio hara necesarios cambios de codigo en todas partes. El lugar correcto para este tipo de validacin 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 diseador de LINQ to SQL como clases parciales con lo que podemos aadir mtodos/eventos/propiedades fcilmente. El modelo de LINQ to SQL ejectuar los mtodos de validacin que podemos implementar. Por ejemplo, Podemos aadir una clase parcial Product a nuestro proyecto que implemente el mtodo parcial OnValidate() que LINQ to SQL llama antes de guardar las entidades de Product. En este mtodo podemos aadir la siguiente regla de negocio para segurarnos que los productos no pueden tener un Reorder Level si el producto es discontinued:

Una vez que aadimos 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 aadir nuevos. Como el <asp:LinqDAtaSource> trabaja contra nuestro modelo de datos, cada actualizacin/insercin/borrado pasar por esta regla de validacin antes de guardar los cambios. No necesitamos hacer nada ms en la capa de presentacin para que se cumpla esta regla se comprobar cada vez que se use nuestro modelo de datos. Aadir un manejador de errores en la capa de presentacin. Por defecto si un usuario usa nuestro GridView para meter una combinacin no vlida de UnitOnOrder/Discontinued, nuestro modelo LINQ to SQL lanzar una excepcin. El <asp:LinqDataSource> capturar la excepcin 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 pgina, 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 aadir la lgica de errores que queramos en la capa de presentacin. Para la aplicacin que estamos viendo, seguramente el mejor lugar para controlar cualquier error de actualizacin 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 excepcin si falla la actualizacin. Podemos aadir el siguiente cdigo para comprobar si ha ocurrido un error, y mostrar un error adecuado en caso de que ocurra:

No hemos tenido que aadir ninguna validacin lgica en nuestra interfaz de usuario. En lugar de eso, estamos obteniendo el error que lanzamos en nuestra lgica de negocio y la estamos usando para mostrar un mensaje adecuado al usuario (Estamos mostrando un error ms genrico).

Tambin le estamos indicando que queramos que el GridView se mantenga en el modo edicin 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 aadir 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 cmo arreglarlo:

Lo bueno de esto es que podemos aadir o cambiar las reglas de negocio sin tener que cambiar nada en la capa de presentacin. Las reglas de validacin, y sus mensajes correspondientes, pueden centralizarse en un lugar en concreto del modelo de datos y se aplicarn en todas partes. Resumen El control <asp:LinqDataSource> nos da una forma fcil 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 aplicacin hemos usado el ORM LINQ to SQL para crear un modelo limpio, orientado a objetos. Aadimos tres contorles ASP.NET a la pgina (un gridView, una lista desplegable, y un errormessage literal), y hemos aadido tres contorles <asp:LinqDataSource> para enlazar a Product, Category y Proveedores:

Escribimos 5 lneas de validacin lgica y 11 lineas para la gestin de errores. El resultado final es una aplicacin web simple que permite a los usuarios filtrar los productos por su categora, ordenar y paginar eficientemente dichos productos, editar los productos y guardarlos (con nuestra reglas de negocio), y borrar productos del sistema (tambin con nuestra lgica 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 tenis los enlaces a los otros post:

Parte 1: Introduccin 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 cmo usar expresiones LINQ para obtener programticamente datos de la base de datos. En el post de hoy veremos cmo 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 cmo actualizar/insertar/borrar datos con SPROCs. SPROC o no SPROC? Esa es la cuestin La pregunta sobre cuando usar el SQL dinmico 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 ms 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 lgica de negocio y reglas de validacin que funcionan tanto si se usa SQL generado dinmicamente o a travs de SPROCs. En el tercer post de esta serie, hablamos sobre cmo podemos escribir expresiones LINQ contra el modelo de LINQ to SQL como el siguiente cdigo:

Cuando escribimos expresiones LINQ como esta, LINQ to SQL ejecutar el SQL dinmico necesario para obtener los objetos de Product que cumplan las restricciones. Como aprenderemos en este post, tambin 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 dinmico 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 cmo usar el diseador LINQ to SQL para crear el siguiente modelo de clases:

Fijaos en las dos partes del diseador. 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 dinmico para trabajar con los objetos de nuestro modelo de datos. Cmo mapear un SPROC en un DataContext de LINQ to SQL

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

Haciendo doble clic en cualquier SPROC se abrir para edicin y podremos ver el cdigo. Por ejemplo, aqu tenis 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 diseador de LINQ to SQL. Automticamente se crear un nuevo mtodo en la clase DataContext:

Por defecto el nombre del nuevo mtodo en la clase DataContext ser el mismo que el del SPROC, y el tipo de datos devueltos se crear automticamente 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 mtodo seleccionndolo en el diseador 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 fcil de usar. Todo lo que tenemos que hacer es llamarlo para obtener los resultados fuertemente tipados: En VB:

En C#:

Adems de poder hacer un bucle sobre los resultados, tambin podemos enlazar los resultados con cualquier control para mostrarlos. Por ejemplo, el siguiente cdigo enlaza los resultados del SPROC a un control <asp:gridview>

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

Mapeando los tipos resultado de los SPROC del modelo de datos En el SPROC CustOrderHist devolva 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 diseador LINQ to SQL defini la clase CustOrderHistResult para representar los resultados. Tambin 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 informacin:

Como ntes podemos crear un mtodo GetProductsByCategory en la clase DataContext que llama a este SPROC arrastrndolo al diseador de LINQ to SQL. Ms que simplemente arrastrar el SPROC al diseador, lo arrastraremos encima de la clase Product:

Con esto, el mtodo GetProductsByCategory devolver una secuencia de objetos Product:

LINQ to SQL seguir los cambios hechos a los objetos que se devuelvan como si fuesen objetos Products obtenidos a partir de expresiones LINQ. Cuando llamemos al mtodo SubmitChanges() todos los cambios hechos a esos objetos se guardarn en la base de datos. Por ejemplo, con el siguiente cdigo obtenemos y cambiamos el precio de todos los productos de una categora aumentndolo en un 90 %:

Para entender cmo funciona el mtodo SubmitChanges() y el seguimiento que se hace de los cambios, y ver cmo podemos aadir lgica de negocio a nuestro modelo de datos leed el cuarto post de esta serie. En el prximo post de esta serie veremos tambin cmo cambiar el SQL generado cuando insertamos/actualizamos/borramos datos con SPROCs personalizados. Lo bueno de todo esto es que el cdigo anterior no habr que cambiarlo si hemos configurado la clase DataContext para que use SPROCs para las actualizaciones -

Manejando resultados mltiples 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 parmetro de entrada:

LINQ to SQL permite crear mtodos auxiliares para devolver Product o Order aadiendo una clase parcial NorthwindDataContext al proyecto que defina un mtodo (que en este caso llamaremos VariablesShapeSample) que invoca al SPROC y devuelve un objeto IMultipleResult: VB:

C#:

Una vez que aadimos este mtodo al proyecto podemos llamarlo y convetir los resultados tanto a una secuencia de Product como de Order: VB:

C#:

Soporte de funciones definidas por el usuario (UDFs) Adems de SPROCS, LINQ to SQL tambin soporta tanto funciones de usuario de valores y de tablas de valores (UDFs). Una vez que aadimos un mtodo a la clase DataContext, podemos usar estas funciones en nuestras consultas LINQ. Por ejemplo, veamos la funcin simple MyUpperFunction:

Podemos arrastrar y soltar desde el explorador de servidores al diseador de LINQ to SQL para aadirlo como un mtodo a nuestro DataContext:

Luego podemos usar esta funcin UDF en expresiones LINQ cuando escribimos consultas contra nuestro modelo LINQ to SQL: VB:

C#:

Si usamos el visualizador de debug de LINQ to SQL del que ya hablamos aqu,podemos ver cmo LINQ to SQL transforma la expresin anterior en una SQL que ejecutar el UDF en la base de datos en tiempo de ejecucin:

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 cmo podemos usar SPROCs para obtener datos y pasarlo entre nuestras clases del modelo. En el prximo post veremos cmo podemos usar SPROCS para sobreescribir la lgica de actualizacin/insercin/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 tenis los enlaces a los otros post:

Parte 1: Introduccin 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.

En la sexta parte vimos cmo 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 cmo 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 cmo usar el diseador de LINQ to SQL de VS 2008 para crear el siguiente modelo de clases:

Aadiendo reglas de validacin a nuestro modelo de clases. Despus de definir nuestro modelo querremos aadir reglas de validacin a nuestro modelo de datos. Podemos hacer esto aadiendo clases parciales a nuestro proyecto y aadir las reglas de validacin en esas clases (vimos cmo hacer esto en la cuarta parte de esta serie).

Por ejemplo, podemos aadir la lgica necesaria para asegurarnos de que el nmero de telfono de los clientes siguen un patrn vlido, 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 mtodos de validacin se ejecutarn cada vez que escribamos cdigo para actualizar nuestros objetos de datos de nuestra aplicacin: VB:

C#:

Aadir un mtodo de ayuda GetCustomer() a nuestro DataContext Una vez que hemos creado nuestro modelo de clases, y que le hemos aadido reglas de validacin, podemos consultar e interactuar con los datos. Podemos hacer esto escribiendo expresiones LINQ sobre nuestro modelo de clases (vimos cmo hacer esto en la tercera parte de esta serie). Tambin 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 mtodos auxiliares que aadiremos a la clase DataContext. Esto lo conseguimos aadiendo una clase parcial a nuestro proyecto. Por ejemplo, podemos aadir un mtodo llamado GetCustomer() que nos permita buscar y obtener objetos Customer de la base de datos a partir del valor CustomerID: VB:

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 validacin, y nos permite consultar, actualizar, insertar y borrar datos. Veamos ahora un escenario simple usndolo para obtener un objeto customer existente, actualizamos el ContactName y el PhoneNumber, y creamos un nuevo objeto Order para asociarlos. El siguiente cdigo hace todo eso en una sola transaccin. LINQ to SQL se asegura de que las reglas de validacin se cumplen ntes de guardar nada en la base de datos:

VB:

C#:

LINQ to SQL monitoriza todas las modificaciones de los objetos que hemos obtenido de la base de datos, y guarda los objetos que aadimos. Cuando llamamos al mtodo DataContext.SubmitChanges(), LINQ to SQL comprueba las reglas que hemos establecido, y genera automticamente la SQL que actualizar el registro de Customer e insertar un nuevo registro en la tabla Orders Un momento Pensaba que este post iba sobre SPROCs Si an estais leyendo, os preguntaris dnde estn los SPROCs en este post. Porque os estoy mostrando el cdigo de arriba que hace que se genere una SQL dinmica? Por qu no os he enseado cmo llamar a un SPROC para hacer las inserciones/actualizaciones/borrados todava? La razn es que el modelo de programacin de LINQ to SQL tanto para trabajar con objetos modelados mediante SPROC es exactamente el mismo que con SQL dinmico. La manera en que aadimos validacin lgica es exactamente igual (as que todas las reglas que hemos aadido a nuestro modelo de datos se aplicarn tambin si usamos SPROCs). El cdigo anterior que hemos usado para obtener un cliente, actualizarlo y aadir un nuevo pedido es exactamente igual tanto si usamos SQL dinmico como si usamos SPROCs. Esta simetra en el modelo de programacin 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 tcnica usar, si SPROC o no. Podemos empezar usando el SQL dinmico que nos da LINQ to SQL para las consultas, inserciones, actualizaciones y borrados. Podemos aadir reglas de validacin a nuestro modelo. Y luego podemos actualizar el modelo de datos para usar SPROCs o no. El cdigo y los test que escribamos contra las clases del modelo de datos sern exctamente iguales. De ahora en adelante veremos cmo podemos actualizar nuestro modelo de datos usando SPROCs para actualizar/insertar/borrar mientras seguimos usando las mismas reglas de validacin y trabajaremos con los mismos cdigos anteriores. Cmo usar SPROCs en inserciones, actualizaciones y borrados Podemos modificar la capa de datos que estamos construyendo para que use SPROCs, en lugar de SQL dinmico de dos maneras: 1. Usando el diseador de LINQ to SQL para configurar grficamente la ejecucin de los SPROCs en las diferentes operaciones o

2. Aadir una clase parcial NorthwindDataContext a nuestro proyecto, y entonces implementar los mtodos
necesarios para la insercin, borrado y actualizacin. (por ejemplo: InsertOrder, UpdateOrder, DeleteOrder) que sern llamados cuando se realize alguna de las operaciones asociadas. Estos mtodos parciales sern pasados a las instancias del modelo de datos que queramos actualizar, y podemos ejecutar tanto SPROC como cdigo SQL para guardarlo.

Cuando usemos la primera aproximacin para configurar grficamente los SPROCs que llamaremos, por debajo se est generando el mismo cdigo (en clases parciales que crea l solo) que escribiramos si elegimos la segunda opcin. En general os recomiendo que usis el diseador de LINQ to SQL para configurar los SPROCs en el 90% de los casos y crear las llamadas personalizadas a procedimientos almacenados en escenarios ms avanzados. Paso 3: Hacer otras inserciones con un SPROC 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 botn derecho y elegimos la opcin Add New Stored Procedure:

Creamos el nuevo procedimiento almacenado que llamaremos InsertOrder que aade una nueva fila order a la tabla Orders:

Fijos que hemos definido el parmetro OrderId como un parmetro de salida. ESto es debido a que la columna OrderID es una columna identidad que se autoincrementa cada vez que se aade un nuevo registro. Quien llame a este SPROC dever pasarle un valor null en ese parmetro y el SPROC devolver en ese parmetro el nuevo valor OrderID (llamando a la funcin SCOPE_IDENTITY() al final del SPROC). Despus de crear el SPROC abrimos el diseador 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 diseador. Esto es lo que haremos con el nuevo SPROC que acabamos de crear:

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 diseador LINQ to SQL, y en las propiedades clicamos el botn del mtodo Insert:

Hacemos clic en el botn y aparecer una ventana que nos permite personalizar las operaciones de insercin:

Fijaos cmo el modo po defecto (Use Runtime) est configurado para usar LINQ to SQL como generador dinmico de las SQL. Para cambiarlo seleccionamos el radio buton Customize y seleccionamos el SPROC InsertOrder de la lista de SPROCS disponibles:

El diseador de LINQ to SQL calcular una lista de parametros para el SPROC que hemos seleccionado, permitindonos mapear las propiedades de nuestra clase Order a los parmetros del SPROC InsertOrder. Por defecto seleccionar el que ms se parezca en el nombre. Podemos cambiarlo si queremos. Una vez que cliquemos en OK est listo. Ahora cada vez que aadamos un nuevo pedido a nuestro DataContext e invoquemos al mtodo SubmitChanges(), se ejecutar el SPROC InsertOrder. Importante: Aunque estemos usando SPROC para la persistencia, el mtodo parcial OnValidate() que creamos (en la primer parte de esta serie) para encapsular las reglas de validacin para los pedidos seguirn ejecutndose antes de realizar cualquier cambio. Es decir, tenemos una forma limpia de encapsular la lgica de negocio y las reglas de validacin 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. Empezamos creando el SPROC UpdateCustomer:

Fijaos que adems de pasar el parmetro @CustomerID, tambin tenemos un parmetro @Original_CustomerID. La columna CustomerID de la tabla Customers no es un campo autoincremental, y puede modificarse cuando hagamos una actualizacin. Por tanto necesitamos ser capaces de decirle al SPROC cual es el CustomerID original y el nuevo CustomerID. Vamos a ver cmo mapeamos esto con el diseador de LINQ to SQL. Veris que estamos pasando un parmetro llamado @Version (que es una marca de tiempo) al SPROC. Es una nueva columna que he aadido a la tabla Customers para ayudarme a controlar la concurrencia optimista. Veremos en ms 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 algn cambio por parte de otro usuario ntes de guardar los datos. Para este ejemplo usaremos una marca de tiempo ya que hace que el cdigo sea mucho ms claro. Una vez que tenemos nuestro SPROC, lo arrastramos y soltamos al diseador LINQ to SQL para aadirlo como mtodo a nuestro DataContext. Seleccionamos la clase Customer y hacemos clic en el botn de la propiedad Update:

Seleccionamos el radio button Customize y seleccionamos el SPROC UpdateCustomer:

Cuando mapeamos las propiedades de los objetos Customer con los parmetros 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 parmetro @CustomerID, y el valor original en el parmetro @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 dinmico. Importante: Aunque ahora estemos usando SPROC, el mtodo parcial OnPhoneChanging() de la clase Customer (que creamos en el primer post de esta serie) para validar los nmeros de telfono 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 validacin a nuestros modelos de datos, y podemos reutilizarlos tanto si usamos SQL dinmico 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 dinmico, podemos ejecutar el mismo cdigo que vimos en el paso 2:

Ahora las actualizacion del objeto Customer, y la insercin del objeto ORder, se estn ejecutando a travs de SPROCs en lugar de SQL dinmico. La lgica de validacin que definimos se siguen ejecutando como antes, y el cdigo sigue siendo exactamente el mismo. Apuntes avanzados cuando usamos SPROCs

Veamos unas cuantas recomendaciones tiles para escenarios con SPROC ms avanzados con LINQ to SQL Uso de parmetros de salida En casos de insercin (Paso 3) hemos visto cmo podemos devolver el nuevo valor OrderID (que es un valor identidad y autoincremental de la tabla Orders) usando un parmetro de salida en el SPROC. No estamos limitados a devolver slo valores de columnas identidad con SPROCs y LINQ to SQL en realidad podemos actualizar y devolver cualquier parmetro. 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 transaccin de todos los cambios asociados a la llamada SubmitChanges(). De manera que nos aseguramos la consistencia de los datos. Podemos escribir cdigo en lugar de usar el diseador para llamar a un SPROC? Como ya coment al principio, podemos usar tanto el diseador de LINQ to SQL para mapear las operaciones con SPROC o podemos aadir mtodos parciales a la clase DataContext programticamente e invocarlos nosotros mismo. Aqu tenis un ejemplo del cdigo que deberamos escribir para sobreescribir el mtodo UpdateCustomer de la clase NorthwindDataContext:

Este cdigo es el que fu generado con el diseador de LINQ to SQL cuando lo usamos para mapear el SPROC y asociarlo a la operacin de Update del objeto Customer. Podemos usarlo como un punto de partida y aadir alguna lgica adicional para hacerlo ms 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 cdigo limpio orientado a objetos para obtener, acutalizar e insertar datos.

Lo mejor de todo es que nos permite disear una capa de datos realmente limpia e independiente de cmo se guardan y cargan los datos de la base de datos. Podemos usar SQL dinmico o SPROCs para esas operaciones. Lo mejor es que el cdigo que use nuestra capa de datos, y todas las reglas de negocio asociadas, sern las mismas sin importar que mtodo 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 tambin para actualizar, insertar y borrar datos. Aqu teneis los enlaces a los diferentes post de la serie:

Parte 1: Introduccin 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 cmo 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 cmo podemos usar expresiones SQL personalizadas para que LINQ to SQL las use en lugar de las que generara l. Uso de expresiones LINQ con LINQ to SQL. Supongamos que hemos usado el diseador 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):

En el tercer post vimos cmo podemos usar LINQ con las nuevas caractersticas 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 aadir un mtodo a la clase DataContext GetProductsByCategory que usa una consulta LINQ para devolver objetos de Products de la base de datos: VB:

c#:

Una vez definido nuestro mtodo de LINQ, podemos escribir el siguiente cdigo para obtener productos e iterar sobre ellos: VB:

Cuando se evala la expresin LINQ del mtodo GetProductsByCategory, el ORM LINQ to SQL ejectuar un SQL dinmico 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 cul es la expresin LINQ que se ejectuar. Uso de consultas SQL personalizadas con LINQ to SQL En el ejemplo de arriba no tenemos que escribir ningn cdigo SQL para consultar y obtener objetos Product fuertemente tipados. LINQ to SQL traduce la expresin 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 mtodo auxiliar ExecuteQuery de la clase DataContext y usar una expresin SQL personalizada que le demos. Usando el mtodo ExecuteQuery El mtodo ExecuteQuery toma una expresin SQL como argumento , con un conjunto de parmetros, 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 cmo queremos devolver los valores de la expresin SQL. Podemos hacer esto pasndole un parmetro tipado al mtodo o usando una versin genrica del mtodo. Por ejemplo, podemos cambiar el mtodo GetProductsByCategory() que creamos ntes -con una expresin LINQ- para que use el mtodo ExecuteQuery para ejectuar un SQL que nosotros le digamos:

VB:

C#:

Ahora podemos llamar al mtodo GetProductsByCategory() de la misma forma que ntes:

De esta manera ser nuestra consulta SQL la que se ejecutar contra la base de datos y no el SQL dinmico que generara la expresin 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 mtodo 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 caracterstcias del metodo ExecuteQuery() es que participa en este tracking de objetos para actualizar el modelo. Por ejemplo, podemos escribir el siguiente cdigo para obtener todos los productos de una categora y rebajar los precios un 10%:

Como dijimos que el tipo de resultado del ExecuteQuery en el mtodo GetProductsByCategory fuese Product, LINQ to SQL sabe cmo guardar los cambios. Y cuando llamemos a SubmitChanges los guardar. SQL personalizado con clases personalizadas. El mtodo ExecuteQuery nos permite especificar cualquier clase como tipo de resultado de la consulta SQL. La clase no tiene porqu haberse creado con el diseador LINQ to SQL, o implementar ninguna interfaz. Por ejemplo, definimos la clase ProductSummary con un subconjunto de las propiedades de Product (fijos que hemos usado la caracterstica depropiedades automticas):

Podramos crear otro mtodo en nuestro DataContext llamado GetProductSummariesByCategory() que nos devuelva objetos de esa clase. Fijos cmo la siguiente SQL obtiene slo un subconjunto de Product El mtodo ExecuteQuery() se encarga de mapea automticamente las propiedades a objetos de la clase ProductSumary:

Ahora podemos invocar a este mtodo e iterar sobre los resultados con el siguiente codigo:

SQL personalizadas para inserciones, actualizaciones y borrados. Adems de usar SQL personalizadas para consultar datos, tambin podemos hacerlas para insertar, actualizar y borrar datos. Esto lo conseguimos creando los mtodos parciales adecuados para cada operacion para la entidad que queramos cambiar en nuestra clase DataContext. Podemos usar el mtodo ExecuteCommand del DataContext para escribir el SQL que queramos. Por ejemplo, para sobreescribir el comportamiento de borrado de la clase Product definimos el siguiente mtodo parcial:

Y si escribimos un cdigo que elimine un producto de la base de datos, LINQ to SQL llamar al mtodo DeleteProduct que ejecutar una SQL personalizada en lugar del SQL dinmico que LINQ to SQL usara:

Resumen El ORM LINQ to SQL genera y ejectua un SQL dinmico para las consultas, actualizaciones, inserciones y borrados contra la base de datos. Para escenarios ms avanzados, o en caso donde queramos un control total sobre el SQL que se ejecuta, tambin 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 tambin para actualizar, insertar y borrar datos. Aqu tenis los enlaces a los diferentes post de la serie: Parte 1: Introduccin 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 cmo podemos enlazar controles de ASP.NET a LINQ to SQL. Tambin vimos cmo usarlo con el control <asp:ListView> (El control asp:ListView (Parte 1 Creacin de una pgina de listado de productos con una CSS limpia)) En ambos artculos las consultas que hacamos eran relativamente sencillas (la clausula where se ejecutaba sobre una tabla simple). En el post de hoy veremos cmo usar toda la potecia de las consultas de LINQ con el control LinqDataSource, y veremos cmo usar cualquier expresion LINQ to SQL con l. Pequea recapitulacin: <asp:LinqDataSource> con una sentencia Where. En estos dos post vimos cmo 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), podramos declarar un control <asp:LinqDataSource> en la pgina con un filtro <where> que devuelve aquellos productos de una categora dada. (especificada a partir del valor categoryid).

Luego, podemos enlazar un <asp:gridView> a este datasource y habilitar la paginacin, edicin y ordenacin.:

Cuando ejecutamos la pgina anterior tendremos un GridView que soportar automticamente la ordenacin, paginacin y edicin sobre el modelo de Produt:

Usando los parmetros del <where> de esta forma funciona muy bien en escenarios tpicos. Pero qu pasa si que el filtrado de Product sea ms complejo? Por ejemplo, Si slo queremos mostrar los productos suministrados por un conjunto dinmico 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 cdigo que queramos para obtener los datos. Esto lo podemos hacer con una expresin LINQ to SQL, o llamar a unprocedimiento almacenado o usar una expresin 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 tenis una consulta LINQ to SQL que obtiene aquellos productos de los proveedores de un conjunto de pases: VB:

C#:

Nota: No tenemos que escribir la consulta en el cdigo del manejador. Una solucin ms limpia sera encapsularla en un mtodo de ayuda al que podramos llamar desde el propio manejador. Esto lo vimos en laparte 8 de esta serie (usando el mtodo GetProductsByCategory).
Ahora, cuando ejecutemos la pgina usando este manejador, slo obtendremos los productos de los proveedores de ciertos pases:

Una de las cosas ms interesantes es que la paginacin y la ordenacin siguen funcionando en nuestro GridView aunque estemos usando el evento Selecting. Esta lgica de paginacin y ordenacin ocurre en la base de datos es decir, slo devolvemos los 10 productos de la base de datos que necesitamos para el ndice actual del GridView (supereficiente). Os estaris preguntando cmo es posible que tengamos una paginacin y ordenacin eficiente incluso cuando lo hacemos con un evento personalizado?. La razn es que LINQ usa el modelo de ejecucin 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 aadirles comportamiento. Podis leer ms 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 an no la hemos ejecutado (ya que no hemos iterado sobre los resultados o llamado a los mtodos ToArray() o ToList()). El LINQDataSource es capaz de aadir automticamente los operadores Skip() y Take() al aconsulta, as como aplicarle una expresin orderby siendo todos estos valores calculados automticamente a partir del ndice de pgina y las preferencias de ordenacin del GridView. Slo entonces el

LINQDataSource ejecuta la expresin LINQ y obtiene los datos. LINQ to SQL se encarga de que la lgica de ordenacin y paginado se haga en la base de datos y que slo se devuelvan 10 filas de productos. Fijos cmo 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 cmo funcionan las actualizaciones con LINQ to SQL, leed laparte cuatro de esta serie, y luego la parte quinta para ver las Updates en acccin. Realizano proyecciones de consultas personalizadas con el evento Selecting. Una de las caractersticas ms poderosas de LINQ es la habilidad de formar o proyectar datos. Podemos hacer esto en una expresin LINQ to SQL para indicar que queremos obtener slo un subconjunto de valores de una entidad, y/o

calcular nuevos valores dinmicamente al vuelo con expresiones personalizadas que definamos. Para leer ms 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 informacin de Product. En el grid queremo mostrar el ProductID, ProductName, Product UnitPrice, el nmero de pedidos de ese producto, y el total de pedidos de ese producto. Podemos calcular estos dos ltimos campos con la siguiente expresin LINQ: VB:

C#:

Nota: El mtodo Sum para calcular el Revenue es un ejemplo de unmtodo de extensin. La funcin es una expresin lambda. El tipo de resultados creados de la consulta LINQ es un tipo annimo - ya que el tipo es inferido de la consulta. Mtodos de extensin, expresiones Lambda, y los tipos annimos son nuevas caractersticas de VB y C# en VS 2008.
El resultado de esta expresin LINQ cuando lo enlazamos al GridView es el siguiente:

Fijaos que la paginacin y la ordenacin sigue funcionando en el GridView aunque estemos usando una proyeccin de LINQ para los datos. Una caracterstica que no funcionar con las proyecciones es el soporte para la edicin. Esto es debido a que estamos haciendo una proyeccin personalizada en el mtodo Selecting, y el LINQDataSource no tiene forma de saber cmo actualizar la entidad. Si queremos aadir soporte para la edicin en este caso, tendremos que crear un control ObjectDataSource (al que le pondremos un mtodo Update personalizado para contorlarlos), o hacer que el usuario navegue a una nueva pgina para hacer la actualizacin y mostrar un DetailsView o FormView enlazado a la entidad Producto para la edicin (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 ms avanzadas, usaremos el mtodo Selecting del LINQDataSource. Esto no permitir crear la lgica que queramos para obtener y filtrar datos LINQ to SQL. Podemos llamar a mtodos para obtener los datos, usar Expresiones LINQ, llamar a procedimientos almacenados o invocar una expresin SQL personalizada para hacer esto.

You might also like