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 Framewor !"rcas#. $qu ten%is los enlaces&

'ropiedades autom(ticas) iniciali*adores de ob+ectos e iniciali*adores de colleciones. ,%todos de e-tensi.n. E-presiones /ambda. Sinta-is de consultas. Tipos $n.nimos

/as caractersticas anteriores hacen que la consulta de datos sea un concepto de primera clase. 0onocemos a este modelo de programaci.n como !/1N2# 3 que viene de .NET /anguage 1ntegrated 2uery. /os desarrolladores pueden usar /1N2 con cualquier 4uente de datos. 'ueden e-presar consultas e4icientemente en los lengua+es de programaci.n que eligan) opcionalmente trans4ormar5incrustar los resultados de las consultas en el 4ormato que quieran) y entonces manipular 4(cilmente los resultados. /os lengua+es habilitados para /1N2 pueden aportar seguridad de tipos y chequeo en tiempo de compilaci.n el las e-presiones de consulta) y desarrollar herramientas que aporten intelisense) debugging) y un gran soporte para re4actoring cuando escriban c.digo de /1N2. /1N2 soporta un modelo de e-tensibilidad muy rico que 4acilita la creaci.n de operadores e4icientes para 4uentes de datos. /a versi.n !"rcas# del .NET Framewor biene con libreras que habilitan /1N2 sobre ob+etos) 6,/ y bases de datos. Qu es LINQ to SQL? /1N2 to S2/ es una implementaci.n de "57,8ob+ect relational mapping) mapeador de ob+etos relacionales9 que viene con la versi.n !"rcas# del .NET Framewor ) y nos permite modelar bases de datos relacionales con clases de .NET. 'odemos consultar bases de datos con /1N2) as como actuali*ar5a:adir5borrar datos de ellas. Modelando bases de datos con LINQ to SQL: Visual Studio !"rcas# viene con un dise:ador de /1N2 to S2/ que nos aporta una 4orma 4(cil de modelar y visuali*ar una base de datos como un modelo de ob+eto de /1N2 to S2/. El pr.-imo post cubrir( en m(s pro4undidad c.mo usar este dise:ador 8pod%is ver %ste video que hice en Enero para verme construir un modelo /1N2 to S2/9. ;sando ese dise:ador /1N2 to S2/ puedo crear 4(cilmente una representaci.n de la base de datos !Northwind#&

El dise:o de arriba de4ine cuatro clases& 'roduct) 0ategory) "rder y "rder<etail. /as propiedades de cada clase mapean las columnas de cada table en la base de datos. 0ada instancia de esa clase representa una 4ila en las tablas. /as 4lechas entre las cuatro clases de arriba representan las asociaciones5relaciones entre las di4erentes entidades. Son tpicamente modeladas como relaciones primary= ey54oreign= ey en la base de datos. /a direcci.n de las 4lechas en el dise:ador indican si la relaci.n es uno=a=uno o uno=a=varios. Se a:adiran propiedades 4uertemente tipadas a las entidades bas(ndose en esto. 'or e+emplo) la clase 0ategory de arriba tiene una relaci.n de uno=a=varios con la clase 'roduct. Esto implica que tendr( una propiedad !0ategories# que es una colecci.n de ob+etos 'roduct con esa categora. /a clase 'roduct entonces tiene una propiedad !0ategory# que apunta a una instancia de la clase 0ategory representando la categora a la que pertenece el producto. El panel de la derecha del dise:ador /1N2 to S2/ contiene una lista de procedimientos almacenados que interactan con nuestro modelo de base de datos. En el e+emplo de arriba hemos a:adido un S'7"0 8'rocedimiento almacenado9

!>et'roducts?y0ategory#. 0omo entrada recibe un category1<) y devuelve una secuencia de 'roduct como resultado. Veremos c.mo llamar a este procedimiento almacenado en un e+emplo. Entendiendo la clase DataContext 0uando puls(is el boton !save# del dise:ador de /1N2 to S2/) Visual Studio generar( clases .NET para representar las entidades y las relaciones de la base de datos que hemos modelado. 'or cada archivo a:adido a nuestra soluci.n por el dise:ador /1N2 to S2/ tambi%n se generar( una clase <ata0onte-t. Esta clase es a traves de la cual reali*aremos las consultas a las entidades de nuestra base de datos. Esta clase tendr( propiedades que representar(n a cada tabla que hemos modelado) as como m%todos para cada procedimiento almacenado que a:adamos. 'or e+emplo) aqu ten%is la clase Northwind<ata0onte-t&

Ejemplos de LINQ to SQL ;na ve* que hemos modelado nuestra base de datos con el dise:ador de /1N2 to S2/) podemos escribir c.digo 4(cilmente para traba+ar con %l. $qu ten%is unos cuantos e+emplos que muestran tareas comunes con datos& 1 Consultando !"oducts de la base de datos

El siguiente c.digo usa una consulta /1N2 para obtener una secuencia 1Enumerable de ob+etos 'roduct. Fi+(os que este c.digo est( consultando a traves de la relaci.n 'roduct50ategory para obtener aquellos productos de la categora !?everages#. 0@&

V?&

# $ctuali%ando un p"oducto en la base de datos& El c.digo siguiente muestra c.mo obtener un producto de la base de datos) actuali*ar su precio) y guardar los cambios en la base de datos& 0@&

V?&

Nota& V? en !"rcas# ?etaA no soporta /ambdas an. 'ero en la ?etaB s =de 4orma que el c.digo anterior se podr( escribir de una 4orma m(s concisa. ' $(adi" una nue)a cate*o"+a , dos nue)os p"oductos en la base de datos& El siguiente c.digo muestra c.mo crear una nueva categora) y entonces crear dos nuevos productos y asociarlos a la nueva categora. /os tres son despu%s guardados en la base de datos. Fi+aos como no necesitamos administrar manualmente las relaciones primary ey54oreign ey. S.lo tenemos que a:adir los ob+etos 'roduct en la colecci.n !'roducts# de la categora) y luego a:adir el nuevo ob+eto 0ategory en la colecci.n de !0ategories# del <ata0onte-t) /1N2 to S2/ sabr( autom(ticamente crear las 'F5FC necesarias& 0@&

- .o"a" p"oductos de la base de datos& El c.digo siguiente muestra c.mo borrar todos los productos Toy de la base de datos&

0@&

V?&

/ Llama" a un p"ocedimiento almacenado& El c.digo siguiente muestra c.mo obtener entidades de la tabla 'roduct sin usar una consulta /1N2) sino llamando al procedimiento almacenado !>et'roducts?y0ategory# que a:adimos a nuestro modelo de datos. Fi+(os que cuando obtenemos los resultados de la tabla 'roduct) podemos actuali*ar5borrarlos y llamar a db.Submit0hanges89 para hacer las modi4icaciones en la base de datos. 0@&

V?&

0 1btene" p"oductos con pa*inado del lado del se")ido" El c.digo siguiente muestra c.mo implementar un paginado e4iciente en el lado servidor como parte de una consulta /1N2. ;sando los operadores S ip89 y Ta e89) s.lo devoleremos AD 4ilas de la base de datos 3 a partir de la 4ila BDD. 0@&

V?&

2es3men: /1N2 to S2/ nos permite modelar la capa de datos de nuestras aplicaciones de una 4orma simple y limpia. ;na ve* que hayamos de4inido nuestro modelo de datos) podemos reali*ar consultas) inserciones) actuali*aciones y borrados sobre ella de 4orma 4(cil y e4iciente.

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


'ublicado en .NET) $S' .NET) /1N2) /1N2 to S2/) Visual Studio a AB&DE am por Fuanma

En la primera parte de la serie de post sobre /1N2 to S2/ habl% sobre !Gqu% es /1N2 to S2/H# y vimos por encima algunos escenarios que permite. En aqu%l post pusimos unos cuantos e+emplos de c.digo donde demostr(bamos c.mo me+orar la parte de datos usando /1N2 to S2/& 0.mo consultar una base de datos. 0.mo actuali*ar 4ilas en una base de datos 0.mo a:adir y relacionar varias 4ilas en una base de datos. 0.mo eliminar 4ilas de la base de datos. 0.mo llamar a procedimientos almacenados. 0.mo obtener datos con paginaci.n en el servidor.

,e+oramos todos estos escenarios usando un modelo de clases de /1N2 to S2/ como %ste&

En este segundo post de la serie vamos a ver en m(s detalle c.mo crear el modelo anterior con /1N2 to S2/. /1N2 to S2/) el dise:ador de /1N2 to S2/) y todas las caractersticas que estamos viendo saldr(n con la versi.n de .NET I.J y en la release de Visual Studio !"rcas#. 'od%is seguir todos los pasos siguientes descarg(ndo tanto Visual Studio !"rcas# ?eta A o Visual Keb <eveloper E-press !"rcas# ?eta A. 'od%is instalar las dos y usarlas sin ningn problema con Visual Studio BDDJ. C"ea" un nue)o modelo de datos LINQ to SQL 'odemos a:adir un modelo de datos de /1N2 to S2/ a un pro+ecto $S'.NET) 0lass /ibrary o Kindows) con la nueva opci.n !$dd New 1tem# seleccionando !/1N2 to S2/#&

Seleccionando !/1N2 to S2/# lan*ar( el dise:ador de /1N2 to S2/) y nos permitir( modelar las clases que representen una base de datos relacional. Tambi%n crear( una clas 4uertemente tipada !<ata0onte-t# que tendr( las propiedades que representar(n cualquier tabla que modelemos de la base de datos) as como m%todos para cada procedimiento almacenado que modelemos. 0omo describimos en la primera parte de esta serie de post) la clase <ata0onte-t es el conducto principal que usaremos tanto para consultar la base de datos como para guardar los cambios que hagamos. $qu ten%is una captura de pantalla de un dise:o /1N2 to S2/ "7, vaco) es lo que ver%is despues de crear un nuevo modelo de datos /1N2 to S2/&

Clases Entidad 4Entit, /1N2 to S2/ nos permite modelar clases que mapeen una base de datos. Estas clases son tpicamente conocidas como !0lases Entidad# 8en ingles !Entity 0lasses#9 y a las instancias se las conoce como !Entidades# 8en ingles !Entities#9. /as clases entidad mapean a tablas de una base de datos. /as propiedades de una clase entidad normalmente mapean las columnas de la tabla. 0ada instancia de una clase entidad representa a una 4ila de una tabla de la base de datos. /as clases entidad de4inidas por /1N2 to S2/ no tienen que derivar de una clase base espec4ica) lo que signi4ica que pueden heredar de cualquier ob+eto que queramos. Todas las clases creadas por el dise:ador de /1N2 to S2/ se de4inen como !clases parciales# 3 con lo que podemos) opcionalmente) a:adir propiedades adicionales) m%todos y eventos. $ di4erencia de la caracterstica de <ataSet5Table$dapter que aporta VS BDDJ) cuando usamos el dise:ador de /1N2 to S2/ no tenemos que especi4icar qu% consultas S2/ se tiene que usar cuando creamos el modelo de datos y la capa de acceso. En lugar de eso) nos centramos en de4inir las clases entidad) c.mo se mapean con la base de datos) y las relaciones entre ellas. /a implementaci.n del "7, de /1N2 to S2/ se encargar( de generar la l.gica de e+ecuci.n S2/ por nosotros en tiempo de e+ecuci.n para que podamos interactuar y usar las entitades de datos. 'odemos usar sinta-is de consultas /1N2 para indicar c.mo consultar nuestro modelo de datos de 4orma 4uertemente tipada. C"ea" clases entidad de la base de datos& Si ya tenemos un esquema de base de datos de4inido) podemos usarlo para crear clases entidad /1N2 to S2/.

/a 4orma m(s sencilla de conseguirlo es abrir la base de datos desde el !Server E-plorer# de Visual Studio) seleccionar las tablas y vistas 8Views9 que queramos modelar) y arrastrarlas al dise:ador /1N2 to S2/&

0uando a:adimos estas dos tablas 80ategories y 'roducts9 y una vista 81nvoices9 de la base de datos !Northwind# al dise:ador de /1N2 to S2/) tendremos las siguientes clases entidad creadas a partir del esquema de la base de datos&

;sando estas clases) podemos e+ecutar todos los e+emplos de c.digo 8e-cepto el de procedimientos almacenados9 que vimos en la primera parte de esta serie sobre /1N2 to S2/. No tenemos que a:adir ningn c.digo adicional o con4iguraci.n para habilitar los escenarios de consulta) inserci.n) actuali*aci.n) borrado) y paginaci.n en el servidor. Nomb"ado , plu"ali%aci5n ;na de las cosas de las que os dar%is cuenta usanto el dise:ador de /1N2 to S2/ es que autom(ticamente !plurali*a# los nombres de las tablas y columnas cuando crea las clases entidad bas(das en el esquema de la base de datos. 'or e+emplo& la tabla !'roducts# del e+emplo se resuelve en una clase !'roduct#) y la tabla !0ategories# se resuelve en la clase !0ategory#. Este nombrado de clases hace que vuestro modelo sea m(s consistente con las convenciones de nomenclatura de .NET) y encuentro bastante til que el dise:ador haga esto por mi 8especialmente cuando a:adimos muchas tablas a nuestro modelo9. Si no os gusta el nombre de una clase o propiedad que el dise:ador ha generado) siempre podr%is cambiarlo por el que quer(is. 'od%is hacerlo editanto el nombre de la entidad5propiedad en el mismo dise:ador o cambiarlo en la re+illa de propiedades&

Esta habilidad de nombrado de entidades5propiedades5asociaciones es muy til en un gran nmero de casos. En particular& A9 0uando cambie el nombre de una tabla5columna de vuestra base de datos. 0omo vuestras entidades tendr(n nombres di4erentes) pod%is decidir actuali*ar las reglas de mapeado y no el c.digo de vuestra aplicaci.n o las consultas para usar esas nuevas tablas5columnas. B9 0uando en el esquema de la base de datos tengais nombres que no son !limpios#. 'or e+emplo) en lugar de usar !auLlname# y !auL4name# para los nombres de las propiedades en una clase entidad) pod%is usar los nombres de !/astName# y !FirstName# en vuestras clases entidad y programar con esos nombres) en ve* de cambiarlo en la base de datos. 2elaciones 0uando arrastremos ob+etos del !server e-plorer# al dise:ador !/1N2 to S2/#) Visual Studio comprobar( las relaciones de clave primaria y a+enas de los ob+etos) y bas(ndose en ellas crear( relaciones por de4ecto entre las di4erentes clases entidad que genere. 'or e+emplo) cuando a:adimos las tablas 'roducts y 0ategories de la base de datos NorthKind al dise:ador /1N2 to S2/ podemos ver que se ha deducido una relaci.n de uno a n entre ellas 8esto se indica con la 4elcha del navegador9&

Esta relaci.n har( que la clase entidad 'roduct tenga una propiedad llamada !0ategory# que los desarrolladores usar(n para acceder a la entidad 0ategory para un 'roduct dado. Tambi%n har( que la clase 0ategory tenga una colecci.n de !'roducts# que permitir( a los desarrolladores obtener todos los productos de una 0ategory.

Si no nos gusta c.mo el dise:ador a nombrado a la relaci.n) siempre podr%mos cambiarlo. S.lo hay que hacer clic en la 4elcha en el dise:ador) ver las propiedades y cambiar el nombre. 2et"asa" la ca"*a /1N2 to S2/ permite a los desarrolladores especi4icar si las propiedades de las entidades deben precargarse o retrasarse hasta el primer acceso. 'odemos personali*ar las reglas de precarga5retraso para las propiedades de las entidades seleccionando cualquier propiedad o asociaci.n en el dise:ador) y en las propiedades poner la propiedad !<elay /oaded# a true o 4alse. 'or poner un e+emplo) imaginemos la clase entidad !0ategory# del modelo anterior. /a tabla !0ategories# de la base de datos !NorthKind# tiene una columna !'icture# que contiene una imagen 8potencialmente grande9 para cada categora) y s.lo queremos esa imagen cuando vaya a usarla 8y no cuando est% haciendo una consulta para obtener los nombres de las categoras en una lista9. 'odramos con4igurar la propiedad 'icture para que se retrase su carga seleccionandola en el dise:ador de /1N2 to S2/ y en las propiedades poner !<elay /oaded# a true&

Nota& $dem(s de con4igurar el signi4icado de la precarga5retraso de las entidades) podemos sobreescribirlo va c.digo cuando hagamos consultas /1N2 en las clases entidad 8lo veremos en el siguiente post de esta serie9. 6sando p"ocedimientos almacenados& /1N2 to S2/ nos permite modelar procedimientos almacenados como m%todos de nuestra clase <ata0onte-t. 'or e+emplo) supongamos que hemos de4inido un procedimiento almacenado simple para obtener la in4ormaci.n de un producto de un category1<&

'odemos usar el server e-plorer de Visual Studio y arrastrar este procedimiento almacenado al dise:ador de /1N2 to S2/ para obtener un m%todo 4uertemente tipado que invocar( a este procedimiento almacenado. Si lo arrastramos encima de la entidad !'roduct# en el dise:ador) el dise:ador declarar( que el procedimiento almacenado devuelve un 1EnumerableM'roductN&

'odemos usar tanto una consulta S2/ 8que generar( una consulta S2/ adhoc9 o invocar el procedimiento almacenado a:adido para obtener las entidades product de la base de datos&

6sa" p"ocedimientos almacenados pa"a actuali%a"7bo""a"7inse"ta" datos& 'or de4ecto /1N2 to S2/ crear( autom(ticamente e-presiones S2/ apropiadas para cuando tengamos que insertar5actuali*ar5borrar entidades. 'or e+emplo) si escribimos el siguiente c.digo /1N2 to S2/ para actuali*ar algunos valores en una instancia de la entidad !'roduct#&

/1N2 to S2/ crear( y e+ecutar( una sentencia !;'<$TE# apropiada para cuando aceptemos los cambios 8Veremos esto en m(s pro4undidad en otros post9.

'odemos de4inir procedimientos almacenados personali*ados para 1NSE7T) ;'<$TE) <E/ETE. 'ara con4igurar esto) hacemos clic en una entidad del dise:ador /1N2 to S2/ y en las propiedades de <elete51nsert5;pdate) en el bot.n !O#) y ponemos un procedimiento almacenado que ya hayamos de4inido.

/o curioso es que el cambio de estas propiedades se est( reali*ando en la capa de mapeo de /1N2 to S2/ 3 lo que implica que la actuali*aci.n del c.digo que vimos (ntes sigue 4uncionando sin tener que hacer ninguna modi4icaci.n. 0on esto libramos a los desarrolladores de que si cambiamos el modelo de datos /1N2 to S2/) no tienen que tocar ningn c.digo para que sigua 4uncionando si deciden poner un procedimiento almacenado personali*ado. 2esumen /1N2 to S2/ provee una 4orma limpia de modelar las capas de datos de nuestras aplicaciones. ;na ve* que tengamos nuestro modelado de datos) podemos reali*ar de 4orma e4iciente consultas) inserciones) actuali*aciones) y borrados sobre %l. 0on el dise:ador de /1N2 to S2/ que viene en Visual Studio y en Visual Keb <eveloper E-press podemos crear y administrar nuestros modelso de datos para /1N2 to S2/ e-tremadamente r(pido. El dise:ador /1N2 to S2/ tambi%n permite una gran 4le-ibilidad que nos permite personali*ar el comportamiento por de4ecto y sobreescribir5e-tender el sistema para que se adapte a nuestras necesidades. En pr.-imos post usaremos este modelo que hemos creado para ver en m(s detalle los procesos de consulta) inserciones) actuali*aciones y borrados. En estos post tambi%n veremos c.mo a:adir validaciones negocio5datos personali*adas a las entidades que hemos dise:ado.

,i e Taulty tiene una gran cantidad de videos sobre /1N2 to S2/ aqu) os recomiendo que los ve(is. $s ten%is una 4orma de aprender viendo c.mo se usa /1N2 to S2/.

LINQ to SQL (3 Parte Consultando la ase de datos)


'ublicado en .NET) $S' .NET) /1N2) /1N2 to S2/) Scott >uthriP a A&DQ pm por Fuanma

El mes pasado empe*% una serie de post sobre /1N2 to S2/. /1N2 to S2/ es un 4ramewor "57, 8"b+ect relational mapping9 que viene como parte del .NET Framewor I.J) que nos permite modelar de 4orma sencilla bases de datos relacionales con clases de .NET. 'odemos usar) por tanto) e-presiones /1N2 tanto para consultar a la base de datos como para actuali*ar5inertar5borrar datos. $qu ten%is los enlaces a los primero dos post de esta serie&

;sando /1N2 to S2/ 8AR 'arte9 /1N2 to S2/ 8BR 'arte 3 <e4iniendo nuestras clases del modelo de datos9

En el post de hoy vamos a ver en m(s detalle c.mo usar el modelo de datos que creamos en la segunda parte) y veremos c.mo usarlo para consultar datos en un proyecto $S'.NET. Modelo de la base de datos No"t89ind con LINQ to SQL En el segundo post de la serie vimos c.mo crear un modelo de clases /1N2 to S2/ usando el dise:ador de /1N2 to S2/ que viene con VS BDDS. $qu ten%is el modelo que creamos a partir de la base de datos de e+emplo Northwind&

1bteniendo p"oductos& ;na ve* que tenemos de4inido nuestras clases del modelo de datos) podemos consultar y obtener 4(cilmente datos de nuestra base de datos. /1N2 to S2/ nos permite esto usando la sint(-is de consultas de /1N2 sobre la clase Northwind<ata0onte-t que creamos con el dise:ador /1N2 to S2/. 'or e+emplo) para obtener e iterar sobre una secuencia de ob+etos 'roduct podemos escribir el siguiente c.digo&

En esta consulta hemos usado la sentencia !where# en nuestra consulta /1N2 para devolver aquellos productos de una categora. Estamos usando el campo5propiedad 0ategory1< del producto para hacer el 4iltro. ;na de las cosas que nos aporta /1N2 to S2/ es que nos da una total 4le-ibilidad en c.mo consultar nuestros datos) y podemos aprovecharnos de las asociaciones que hicimos cuando modelamos las clases de /1N2 to S2/ para hacer consultas m(s naturales y ricas sobre la base de datos. 'or e+emplo) podemos modi4icar el 4iltro de la consulta por el 0ategoryName en lugar de por el 0ategory1< con la siguiente consulta /1N2&

Fi+(os en c.mo estamos usando la propiedad !0ategory# de cada ob+eto 'roduct para 4iltrarlos por 0ategoryName. Esta propiedad 4ue creada autom(ticamente por /1N2 to S2/ ya que modelamos las clases 0ategory y 'roduct con una relaci.n !varios a uno# en la base de datos. 'or poner otro e+emplo del uso de las relaciones de nuestro modelo) podramos escribir la siguiente consulta /1N2 para obtener aquellos productos que tengan m(s de cinco .rdenes para ellos&

Fi+(os c.mo usamos la colecci.n !"rder<etails# que /1N2 to S2/ cre. en cada clase 'roduct 8debido a la relaci.n A a varios que modelamos en el dise:ador /1N2 to S2/9. :isuali%ando consultas LINQ to SQL en el debu**e" /os "7, como /1N2 to S2/ administran autom(ticamente la creaci.n y la e+ecuci.n del c.digo S2/ cuando reali*amos consultas o actuali*aciones sobre su modelo de ob+etos. ;na de los mayores preocupaciones que tienen los desarrolladores sobre los "7,s es !Gpero qu% c.digo S2/ se est( e+ecutandoH# ;na de las cosas que hace /1N2 to S2/ es poder ver e-(ctamente qu% c.digo S2/ se est( e+ecutando cuando e+ecutamos nuestra aplicaci.n con el debugger. 0on la beta B de VS BDDS podemos usar el nuevo plug=in de visuali*aci.n /1N2 to S2/ para ver 8y testear9 cualquier consulta /1N2 to S2/. Simplemente a:adimos un brea point y pasamos el rat.n por encima y hacemos clic en la lupa para visuali*ar esa consulta&

ESto nos mostrar( un cuadro de di(logo que nos dir( e-actamente la S2/ que /1N2 to S2/ usar( cuando se e+ecute la consulta para obtener los ob+etos 'roduct&

Si pulsamos el bot.n !E-ecute# de este di(logo nos permitir( evaluar el S2/ dentro del debugger y nos mostrar( los resultados de la base de datos&

"bviamente esto hace realmente 4(cil ver qu% l.gica de consultas S2/ est( reali*ando /1N2 to S2/. Fi+(os que podemos sobreescribir la S2/ que /1N2 to S2/ e+ecutar( si queremos cambiarlo = sin embargo) en el TSU de los casos creo que os dareis cuenta de que el c.digo S2/ que /1N2 to S2/ e+ecuta es realmente bueno. Enla%ando consultas LINQ to SQL a cont"oles $S!&NE; /os resultados de las consultas /1N2 implementa la inter4a* 1Enumerable 3 la cual es una inter4a* que los controles de servidor de $S'.NET soportan para enla*ar datos. /o que implica que podemos enla*ar los resultados de cualquier consulta /1N2) /1N2 to S2/) o /1N2 to 6,/ a cualquier control $S'.NET. 'or e+emplo) podemos declarar un control Masp&gridviewN en una p(gina .asp- de la siguiente 4orma&

/uego) podemos enla*ar los resultados de la consulta /1N2 to S2/ que escribimos antes&

Esto generar( una p(gina como la siguiente&

2est"in*iendo los "esultados de la consulta& Vasta ahora) cuando evaluamos una consulta de productos) estamos obteniendo por de4ecto todas las columnas de datos necesarias para cubrir la entidad de 'roduct. 'or e+emplo) esta consulta para obtener productos&

El resultado de esta consulta es&

Normalmente s.lo queremos un subcon+unto de los datos de cada producto. 'odemos usar la nueva caracterstica que /1N2 y los compiladores de 0@ y V? tienen para indicar que s.lo queremos un subcon+unto de los datos) modi4icando la consulta /1N2 to S2/ de la siguiente 4orma&

0on esto obtendremos un subcon+unto de los datos que se obtienen de la base de datos 8como vemos con el visor del debugger9&

/o realmente til de /1N2 to S2/ es que podemos aprovecharnos de las asociaciones entre clases de nuestro modelo de datos cuando restringimos los datos. Esto nos permite e-presar consultas tiles y muy e4icientes. 'or e+emplo) la siguiente consulta obtiene los 1< y los nombres de la entidad 'roduct) el nmero total de pedidos que hemos hecho de productos) y los suma al total de pedidos de 'roductos&

/a e-presi.n a la derecha de la propiedad !7evenue# es un e+emplo del uso delm%todo de e-tensi.n !Sum# de /1N2. Toma una e-presi.n /ambda que devuelve el valor de cada pedido de producto como argumento. /1N2 to S2/ es listo y es capa* de trans4ormar la e-presi.n /1N2 anterior al siguiente S2/ cuando es evaluado 8con el visor del debugger9&

/a sentencia S2/ anterior hace que los valores Num"rders y 7evenue se calculen dentro del servidor S2/) y devuelve los siguientes valores de la base de datos 8realmente r(pido9&

'odemos enla*ar el resultado anterior a nuestro gridview&

?TK 3 en caso de que os lo pregunt%is) tenemos intellisense en VS BDDS cuando escribimos estos tipos de restricciones en las consultas /1N2&

En este e+emplo estamos declarando un tipo an.nimo que usa la iniciali*aci.n de ob+etos para amoldar y de4inir la estructura del resultado. W seguimos teniendo intellisense en VS BDDS) chequeo de compilaci.n y soporte para re4actoring con estos tipos anonimos&

!a*inando los "esultados de la consulta&

;na de las necesidades m(s comunes en entornos web es la posibilidad de hacer e4icientemente la paginanci.n en las inter4aces de usuario. /1N2 tiene dos m%todos de e-tensi.n que permite hacer esto de 4orma 4(cil y e4iciente 3 los m%todos S ip89 y Ta e89. 'odemos usar los m%todos S ip89 y Ta e89 para indicar que s.lo queremos devolver AD ob+etos producto 3 desde la 4ila que le pasemos como argumento&

Fi+(os que no a:adimos ni S ipt89 ni Ta e89 en la primera consulta 3 sino que lo hacemos despu%s de la consulta 8cuando lo enla*amos a la 4uente de datos del >ridView9. ,uchos me preguntan !Gpero esto no signi4ica que primero obtiene todos los datos de la base de datos y luego hace la paginaci.n 8esto es malo9H# No. /a cuesti.n es que /1N2 usa un modelo de e+ecuci.n en di4erido) es decir) la consulta no se e+ecuta hasta que se itera sobre los resultados. ;no de los bene4icios de este modelo de e+ecuci.n en di4erido es que nos permite crear consultas en varias lneas de c.digo 8lo que me+ora la claridad9. Tambi%n nos permite crear las consultas despu%s de otras 3 lo que nos permite composiciones m(s 4le-ibles y reutili*aci.n. ;na ve* que tenemos el m%todo ?ind'roduct89) podemos escribir el siguiente c.digo en nuestra p(gina para obtener el ndice de inicio de la consulta y hacer que los productos sean paginados y mostrados en el gridview&

Esto nos dar( una p(gina de productos) 4iltrada para mostrar aquellos productos que tengan m(s de cinco pedidos) mostrando datos calculados din(micamente) y que son paginables a partir de una cadena de consulta&

Nota& 0uando traba+amos contra S2/ BDDJ) /1N2 to S2/ usar( la 4unci.n S2/ 7"KLN;,?E789 para crear toda la l.gica de paginaci.n en la base de datos. Esto nos asegura que s.lo devolver( las AD 4ilas de datos que queremos mostrar en la p(gina&

Esto hace realmente 4(cil y e4iciente navegar por grandes cantidades de datos. 2esumen Vemos visto por encima alguna de las cosas que /1N2 to S2/ nos o4rece. 'ara aprender m(s sobre e-presiones /1N2 y las nuevas caractersticas de consultas que traen los compiladores de 0@ y V? con VS BDDS) leed estos post&

Nuevas caractersticas de la nueva versi.n de 0@ "rcas ,%todos de e-tensi.n. E-presiones /ambda Sinta-is de consultas Tipos an.nimos

LINQ to SQL (! Parte) "ctuali#ando la ase de datos


'ublicado en .NET) $S' .NET) /1N2) /1N2 to S2/) Scott >uthriP) S2/) Visual Studio a J&DB pm por Fuanma

En las ltimas semanas he escrito una serie de post sobre /1N2 to S2/. /1N2 to S2/ es un "57,8ob+ect relational mapper9 integrado en la versi.n I.J del 4ramewor de .NET) y nos permite modelar 4(cilmente bases de datos relacionales en clases de .NET. 'odemos usar e-presiones /1N2 tanto para consultar la base de datos como para actuali*ar) insertar y borrar datos. $qu ten%is los lin s a los tres primeros post&

'arte A& 1ntroducci.n a /1N2 to S2/ 'arte B& <e4iniendo el modelo de datos. 'arte I& 0onsultando la base de datos

En el post de hoy veremos c.mo usar el modelo de datos que hemos creado) y usarlo para actuali*ar) insertar y borrar datos. Tambi%n veremos c.mo integrar reglas de negocio y crear l.gica de validaci.n personali*ada con nuetro modelo de datos. Modelado de la base de datos No"t8<ind con LINQ to SQL En la segundo post de esta serie) vimos c.mo crear el modelo de clases con el dise:ador de /1N2 to S2/ que trae VS BDDS. $qu ten%is el modelo que creamos a partir de la base de datos de e+emplo Northwind que usaremos en este post&

0uando de4inimos el modelo de4inimos cinco clases& 'roduct) 0ategory) 0ustomer) "rder y "rder<etail. /as propiedades de cada clase mapean las di4erentes columnas de las tablas correspondientes en la base de datos. 0ada instancia de cada clase es una entidad que representa una 4ila de cada tabal. 0uando de4inimos nuestro modelo de datos) el dise:ador /1N2 to S2/ cre. una clase llamada <ata0onte-t que proporciona todo lo necesario para poder consultar5actuali*ar la base de datos. En nuestro e+emplo) esta clase se llama Northwind<ata0onte-t. Xsta clase tiene unas propiedades que representan cada tabla modelada de la base de datos 8en concreto& 'roducts) 0ategories) 0ustomers) "rders y "rder<etails9. 0omo vimos en el tercer post de esta serie) podemos usar e-presiones /1N2 para consultar y obtener datos usando la clase Northwind<ata0onte-t./1N2 to S2/ traduce autom(ticamente estas e-presiones /1N2 al c.digo S2/ apropiado en tiempo de e+ecuci.n.

'or e+emplo) la siguiente e-presi.n devuelve un ob+eto 'roduct buscando el nombre del producto&

/a siguiente consulta nos devuelve todos los productos de la base de datos que no han sido pedidos) y cuyo precio es mayor de ADD d.lares&

Estamos usando la asociaci.n !"rder<etails# de cada producto como parte de la consulta s.lo para obtener aquellos productos que no se han pedido. Se*ui" los cambios , DataContext&SubmitC8an*es4 0uando creamos consultas y obtenemos ob+etos como en los e+emplos anteriores) /1N2 to S2/ estar( pendiente de los cambios o actuali*aciones que les hagamos a los ob+etos. 'odemos hacer tantas consultas y cambios como queramos usando la clase <ata0onte-t de /1N2 to S2/) sabiendo que dichos cambios ser(n supervisados a la ve*&

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

<espu%s de reali*ar los cambios que queramos a los ob+etos que hemos obtenido con /1N2 to S2/) podemos llamar al m%todo !Submit0hanges89# de nuestro <ata0onte-t para guardar los cambios en nuestra base de datos. 0on esto) /1N2 to S2/) creara y e+ecutar( las sentencias S2/ apropiadas para actuali*ar la base de datos.

'or e+emplo) el siguiente c.digo actuali*a el precio y las unidades en stoc del producto !0hai# en la base de datos&

0uando llamamos al m%todo northwind.Submit0hanges89) /1N2 to S2/ crear( y e+ecutar( las sentencias !;'<$TE# de S2/ necesarias para guardar las propiedades modi4icadas. 0on el siguiente c.digo iteramos sobre los productos menos populares y caros y ponemos la propiedad !7eorder/evel# a cero.

0uando llamamos al m%todo northwind.Submit0hanges89) /1N2 to S2/ crea y e+ecuta las sentencias ;'<$TE de S2/ necesarias para modi4icar los productos a los que hemos modi4icado la propiedad 7eorder/evel. Vemos que si no se ha modi4icado alguna propiedad de un 'roduct con la asignaci.n anterior) /1N2 to S2/ no e+ecutar( ninguna actuali*aci.n para ese ob+eto. 'or e+emplo 3 si el precio del producto !0hai# era B dolares) y el nmero de unidades en stoc era cuatro) la llamada a Submit0hanges89 no actuali*ara esos valores. S.lo los productos cuyo 7eorder/evel no era D se actuali*ar(n. Ejemplos de inse"ci5n , bo""ado $dem(s de poder actuali*ar la base de datos) /1N2 to S2/ tambi%n nos permite insertar y eliminar datos. Esto lo conseguimos a:adiendo o eliminando ob+ectos de las colecciones disponibles en <ata0ontest) y luego llamar al m%todo Submit0hanges89. /1N2 to S2/ !monitori*ar(# esas inserciones y borrados) y generar( el c.digo S2/ necesario cuando se invoque a Submit0hanges89 "#adiendo un producto

'odemos a:adir un producto a la base de datos creando un nuevo ob+eto !'roduct#) iniciali*ando sus propiedades y a:adirlo a la colecci.n !'roducts# de nuestro <ata0onte-t&

0uando llamemos a Submit0hanges89 se a:adir( una nueva 4ila en la tabla de productos. $orrando productos <e la misma 4orma que a:adimos un nuevo producto a la base de datos a:adiendo un ob+eto 'roduct a la colecci.n 'roducts del <ata0onte-t) tambi%n podemos borrar productos borr(ndolos de esa misma colecci.n&

/o que estamos haciendo es obtener una secuencia de productos !alternados# de la tabla) es decir) no ordenados por ninguna e-presi.n /1N2) y luego esa secuencia se la pasamos al m%todo 7emove$ll89 de la colecci.n !'roducts#. 0uando llamamos a Submit0hanges89 todos esos productos ser(n borrados de la tabla $ctuali%aciones , "elaciones /o que hace que los "57,Ys como /1N2 to S2/ sean tan 4le-ibles es que tambi%n nos permiten modelar las relaciones entre las tablas. 'or e+emplo) 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 con+unto de pedidos en cada cliente. Wa vimos c.mo modelar las relaciones en la segunda parte de esta serie de post. /1N2 to S2/ nos permite aprovechar estas relaciones tanto para consultar como para actuali*ar nuestros datos. 'or e+emplo) con el siguiente c.digo creamos un nuevo producto y lo asociamos con la categora !?everages#&

Estamos a:adiendo el ob+eto producto en la colecci.n de categoras de productos. Esto indicar( que hay una relaci.n entre dos ob+etos) y har( que /1N2 to S2/ mantenga autom(ticamente las relaciones de clave primaria5a+ena entre los dos cuando llamemos a Submit0hanges89. Veamos otro e+emplo para ver c.mo /1N2 to S2/ nos ayuda a mantener limpio el c.digo re4erente a las relaciones entre las tablas. En el siguiente e+emplo estamos creando un nuevo pedido para un cliente e-istente. <espu%s de rellenar las propiedades necesarias) podemos crear dos ob+etos de detalles de pedido y asociarlo a un pedido de un cliente y actuali*aremos la base de datos con todos los cambios&

0omo vemos) el modelo de programaci.n que hemos usado para hacer todo esto es realmente limpio y orientado a ob+etos. ;"ansacciones ;na transacci.n es un servicio de la base de datos que garanti*a que un con+unto de acciones individuales van a suceder de 4orma at.mica 3 es decir) o se pueden completar todas o si hay alguna que 4alle) todas las demas se descartar(n) y el estado de la base de datos ser( el mismo que (ntes de comen*ar la transacci.n. 0uando llamemos a Submit0hanges89) las actuali*aciones se mapean en una nica transacci.n. Es decir) la base de datos no tendr( nunca un estado inconsistente si hacemos muchos cambios 3 tanto si se hacen las actuali*aciones como si no. Si no hay ninguna transacci.n en curso) el ob+eto <ata0onte-t empe*ar( una transacci.n de la base de datos para guardar las actuali*aciones que hagamos con Submit0hanges89. 'ero /1N2 to S2/ tambi%n nos permite de4inir e-plcitamente y usar nuestro propio sistema de transacciones 8introducido en la versi.n B.D de .NET9. Esto hace m(s 4(cil an integrar c.digo /1N2 to S2/ con el c.digo de acceso a datos que ya tengamos. Tambi%n nos permite encolar recursos que no son propios de la base de datos en la misma transacci.n = por e+emplo& podemos enviar un mensage ,S,2) actuali*ar el sistema de archivos 8usando el nuevo soporte transaccional de sistemas de archivos9) etc 3 y enla*ar todas estas tareas en una sola transacci.n a la hora de actuali*ar la base de datos :alidaci5n , l5*ica de ne*ocio ;na de las cosas m(s importantes que los desarrolladores tienen que hacer cuando traba+an con datos es incorporar validaci.n y reglas de negocio. /1N2 to S2/ tiene varias 4ormas para hacer que los desarrolladores puedan hacer eso de 4orma 4(cil y clara. /1N2 to S2/ nos permite a:adir esta validaci.n l.gica una ve*. <e 4orma que no tendremos que repetir esa l.gica en varios sitios) con lo que conseguimos un modelo de datos m(s mantenible y m(s claro. Sopo"te de )alidaci5n de es=uemas 0uando de4inimos el modelo de clases de datos con el dise:ador de /1N2 to S2/ de VS BDDS) se a:adir(n algunas reglas de validaci.n obtenidas del esquema de las tablas de la base de datos. /os tipos de datos de las propiedades de las clases del modelo de datos coincidir(n con el esquema de la base de datos. 0on esto tendremos errores de compilaci.n si intentamos asignar un booleano a un valor decimal) o si convertirmos tipos num%ricos incorrectamente. Si una columna en la base de datos est( marcada como nullable) la propiedad correspondiente que crea el dise:ador de /1N2 to S2/ ser( un tipo nullable. /as columnas marcadas como no nullables lan*ar(n e-cepciones si no les

asignamos ningun valor. /1N2 to S2/ tambi%n se asegurar( que de que los valores identidad5unicos se asignan correctamente. "bviamente podemos usar el dise:ador /1N2 to S2/ para sobreescribir los valores por de4ecto del esquema si queremos 3 pero por de4ecto) las tendremos autom(ticamente sin tener que hacer nada. /1N2 to S2/ tambi%n comprueba los valores de los par(metros de las consultas S2/) de manera que no tendremos que preocuparnos por los ataques de inyecci.n de S2/. Sopo"te pa"a )alidaci5n pe"sonali%ada de p"opiedades /a validaci.n de datos a trav%s de esquemas es muy til) pero no suele ser su4iciente en escenarios reales. 1maginemos que en la base de datos Northwind tenemos una propiedad !'hone# en la clase !0ustomer# que est( de4inida en la base de datos como nvarchar. ;sando /1N2 to S2/ podemos escribir el siguiente c.digo para actuali*arlo con un nmero de tel%4ono v(lido&

El problema que nos encontraramos) sera que el siguiente c.digo sigue siendo v(lido desde el punto de vista de un esquema S2/ 8ya que sigue siendo una cadena) no un nmero de tel%4ono v(lido9.

'ara no permitir que no se puedan meter nmeros de tel%4ono err.neos en nuestra base de datos) podemos a:adir una regla de validaci.n personali*ada a la clase 0ustomer de nuestro modelo de datos. Es realmente 4(cil) todo lo que necesitamos hacer es a:adir una nueva clase parcial a nuestro proyecto que de4ina el siguiente m%todo&

Este c.digo usa dos caracteristicas de /1N2 to S2/& A. Todas las clases que genera el dise:ador /1N2 to S2/ son !parciales# 3 es decir) podemos a:adir m%todos adicionales) propiedades) y eventos 8en archivos separados9. $s podemos e-tender nuestro modelo de clases creada por el dise:ador de /1N2 to S2/ con reglas de validaci.n y m%todos au-iliares que de4inamos. No es necesario ninguna con4iguraci.n.

B. /1N2 to S2/ e-pone una serie de puntos de e-tensi.n en el modelo de datos que podemos usar para a:adir
validaci.n l.gica. ,uchos de estos puntos de e-tensi.n usan la nueva caracterstica llamada !m%todos parciales# que viene con V? y 0@ en VS BDDS ?etaB. Kes <yer el equipo de 0@ ha escrito un post e-plicando c.mo va esto de los m%todos parciales. En nuestro e+emplo de validaci.n) estamos usando el m%todo parcial "n'hone0hangin que se e+ecuta cada ve* que se cambia el valor de la propiedad #'hone# de un ob+eto !0ustomer#. 'odemos usar este m%todo para validar la entrada de datos 8en este caso estamos usan una e-presi.n regular9. Si todo va bien) /1N2 to S2/ asumir( que el valor es v(lido. Si hay algn problema con el valor) podemos lan*ar una e-cepci.n en el m%todo de validaci.n 3 que har( que la asignaci.n no se haga. Sopo"te pa"a )alidaci5n pe"sonali%ada de objetos entidad& En el punto anterior hemos visto c.mo a:adir validaci.n a una propiedad individual de nuestro modelo de datos. Sin embargo) algunas veces) necesitamos5queremos validar validar multiples propiedades de un ob+eto. Veamos un e+emplo) tenemos un ob+eto "rder y queremos poner las propiedades !"rder<ate# y !7equired<ate#&

Este c.digo es legal desde el punto de vista de S2/ 3 aunque no tenga ningn sentido la propiedad de 4echa de entrega) que era para ayer. /1N2 to S2/ en ?etaB nos permite a:adir reglas de validaci.n a nivel de entidad para corregir este tipo de errores. 'odemos a:adir una clase parcial para nuestra entidad !"rder# e implementar el m%todo parcial "nValidate89 que se invocar( (ntes de que se guarden los datos en la base de datos. <e esta 4orma) podemos acceder y validar todas las propiedades de nuestro modelo de datos&

<e esta 4orma podemos validar cualquiera de las propiedades de la entidad 8incluso obtener acceso de s.lo lectura a los ob+etos asociados9) y lan*ar una e-cepci.n si el valor es incorrecto. 0ualquier e-cepci.n lan*ada desde el m%todo "nValidate89 abortar( cualquier cambio que queramos hacer en la base de datos) y deshacer todos los cambios hechos en la transacci.n actual. :alidaci5n en los mtodos de inse"ci5n7actuali%aci5n7bo""ado& $ menudo necesitamos a:adir validaci.n espec4ica en los m%todos de inserci.n) actuali*aci.n o borrado. /1N2 to S2/ nos lo permite a:adiendo una clase parcial que e-tienda a la clase <ata0onte-t e implementar m%todos parciales para personali*ar la l.gica de inserci.n) actuali*aci.n y borrado de las entidades de nuestro modelo de datos. Estos m%todos ser(n llamados autom(ticamente cuando invoquemos a Submit0hanges89. 'odemos a:adir la validaci.n l.gica que estimemos oportuna con estos m%todos 3 y si todo va bien) /1N2 to S2/ continar( guardando los datos en la base de datos 8llamando al m%todo de <ata0onte-t !E-ecute<ynamic6WZ#9.

'odemos a:adir m%todos que se invocar(n autom(ticamente cuando se vayan a crear5actuali*ar5borrar datos. 'or e+emplo) supongamos que queremos crear un nuevo pedido y asociarlo con un cliente e-istente&

0uando llamamos a northwind.Submit0hanges89) /1N2 to S2/ determinar( que es necesario guardar el nuevo ob+eto "rder) y e+ecutar( nuestro m%todo parcial !1nsert"rder#. $)an%ado: :iendo la lista de cambios de la t"ansacci5n

Vay veces que no nos interesa a:adir validaci.n l.gica a elementos individuales) sino que queremos ser capaces de ver toda la lista de cambios que est(n ocurriendo en una transacci.n. <esde la ?etaB de .NET I.J) /1N2 to S2/ nos permite acceder a la lista de cambios a trav%s del m%todo <ata0onte-t.>et0hange/ist89. Nos devolver( un ob+eto 0hange/ist que e-pone una serie de colecciones de adiciones) borrados y modi4icaciones que se han hecho. ;na apro-imaci.n que podemos hacer en algunos escenarios es crear una clase parcial de la clase <ata0onte-t y sobreescribir su m%todo Submit0hange89. 'odemos obtener la lista de 0hange/ist89 para las operaciones de actuali*aciones y crear cualquier validaci.n que queramos&

Este e+emplo es un caso de uso avan*ado 3 pero es interesante saber que siempre podremos e-tender y aprovecharnos de esta 4orma de las nuevas caractersticas de /1N2 to S2/. $dminist"ando cambios simult>neos con concu""encia optimista& ;na de las cosas en las que tenemos que pensar los desarrolladores en entornos multi=usuarios es c.mo administrar las actuali*aciones de los mismos datos en la base de datos. 'or e+emplo) imaginemos que tenemos dos usuarios que obtienen un ob+eto product) y uno de ellos cambia el 7eorder/evel a D mientras que el otro lo pone a A. Si ambos usuarios guardan esos cambios en la base de datos) el desarrollador tiene que decidir c.mo tratar ese con4licto. ;na soluci.n es de+ar que sea el ltimo que lo guarda 3 es decir) que el valor que el primer usuario guard. se perder( sin que %ste se de cuenta. Esta es una soluci.n muy pobre 8e incorrecta9. "tra soluci.n que permite /1N2 to S2/ es usar el modelo de concurrencia optimista) es decir) /1N2 to S2/ detectar( autom(ticamente si el valor original de la base de datos ha sido actuali*ado por alguien (ntes que se guarden los nuevos datos. /1N2 to S2/ nos da una lista de con4lictos de valores cambiados al desarrollador y nos permite tanto

hacer lo que queramos como avisar al usuario de la aplicaci.n para que nos indique el propio usuario lo que quiere hacer. Wa veremos en m(s detalle este tema en un pr.-imo post. 6so de p"ocedimientos almacenados o l5*ica SQL pe"sonali%ada pa"a inse"ta"? actuali%a" , bo""a"& ;na de las preguntas que tienen los desarrolladores 8en especial los <?$s9) que suelen escribir procedimientos almacenados con S2/ personali*adas) cuando ven /1N2 to S2/ por primerave* es& !Gpero c.mo podemos tener control absoluto del S2/ que se est( e+ecutandoH#. /as buenas noticias son que /1N2 to S2/ tiene un modelo muy 4le-ible que nos permite sobreescribir el S2/ que se est( e+ecutando) y llamar a los procedimientos almacenados que desarrollemos para a:adir) actuali*ar o borrar datos. /o realmente increible es que podemos empe*ar de4iniendo nuestro modelo de datos y de+ar que /1N2 to S2/ administre las inserciones) actuali*aciones y borrados. ;na ve* hecho esto) podemos personali*ar el modelo de datos para que use nuestros propios procedimientos almacenados o nuestras sentencias S2/ 3 sin tener que cambiar nada de la l.gica de aplicaci.n que estamos usando para nuestro modelo de datos) ni cambiar nada de las validaciones ni de la l.gica de negocio. Esto nos da una gran 4le-ibilidad a la hora de construir nuestra aplicaci.n. <e+aremos para otro post c.mo personali*ar los modelos de datos con procedimientos almacenados o sentencias S2/. 2esumen& Este post presenta un buen resumen sobre c.mo podemos usar /1N2 to S2/ para actuali*ar nuestra base de datos e integrar de una 4orma clara validaci.n de datos y l.gica de negocio. 0reo que encontrar%is que /1N2 to S2/ incrementa mucho la prouctividad a la hora de traba+ar con datos) y nos permite escribir c.digo orientado a ob+eto claro en el acceso a datos.

LINQ to SQL ($ Parte) %nla#ar controles de interfa# de usuario con el "SP&Lin'DatSource


'ublicado en .NET) $S' .NET) /1N2) /1N2 to S2/) Scott >uthriP) S2/) Visual Studio a AD&QI pm por Fuanma

En las ltimas semanas he escrito una serie de post sobre /1N2 to S2/. /1N2 to S2/ es un "57, que viene con la versi.n I.J del 4ramewor .NET) y nos permite modelar bases de datos relacionales con clases de .NET. 'odemos usar e-presiones /1N2 para consultar la base de datos) as como actuali*ar) insertar y borrar datos. $qu ten%is los lin s a los post anteriores&

'arte A& 1ntroducci.n a /1N2 to S2/ 'arte B& <e4iniendo el modelo de datos. 'arte I& 0onsultando la base de datos

'arte Q& $ctuali*ando la base de datos.

En estos post hemos visto c.mo podemos usar /1N2 to S2/ program(ticamente para consultar y actuali*ar nuestra base de datos. En el post de hoy veremos el nuevo control Masp&/inq<ataSourceN de la nueva versi.n del .NET Framewor 8I.J9. Este control es una nueva 4uente de datos para $S'.NET 8como los controles "b+ect<ataSource y S2/<ataSource de $S'.NET B.D9 que nos va a permitir enla*ar controles de la inter4a* de usuario a nuestro modelo de datos /1N2 to S2/. $plicaci5n de ejemplo =ue const"ui"emos& El e+emplo que veremos se trata de una aplicaci.n muy simple que nos va a permitir editar los datos de la tabla products&

/a aplicaci.n le da al usuario las siguientes opciones de gesti.n&

A. B. I. Q. J.

Filtrado de productos por categoras. "rdenar los productos haciendo clic en la cabecera de las columnas 8Nombre) 'recio) unidades en stoc ) etc9 Navegar en por los productos de AD en AD. Edici.n de los detalles de cualquier producto. ?orrar productos de la lista.

/a aplicaci.n web la implementaremos con un modelo de datos muy limpio creado con el "7, /1N2 to S2/. Todas las reglas de negocio y las validaciones l.gicas se implementar(n en el la capa de datos 3 y no en la capa de presentaci.n ni en ninguna p(gina web. 0on esto conseguiremos& A9 ;n con+unto consistente de reglas de negocio que ser(n usadas en toda la aplicaci.n) B9 escribiremos menos c.digo y me+or an) no lo repetiremos y I9 podremos cambiar las reglas de negocio cuando queramos sin tener que actuali*ar ese c.digo en miles de sitios en toda la aplicaci.n. Tambi%n aprovecharemos el soporte de paginado y ordenaci.n de /1N2 to S2/ para asegurarnos que tales operaciones no se reali*an en la capa intermedia) sino en la base de datos 8es decir) s.lo obtendremos AD productos de la base de datos en cada momento 3 no estamos obteniendo miles de 4ilas y orden(ndolas5pagin(ndolas en el servidor web9. Qu es el cont"ol @asp:Lin=DataSou"ceA , c5mo nos a,uda? El control Masp&/inq<ataSourceN es un control de $S'.NET que implementa elpatr.n <ataSource0ontrol que se introdu+o con $S'.NET B.D. Es similar a los controles "b+ect<ataSource y Sql<ataSource en que puede enla*ar un control $S'.NET en una p(gina con la base de datos. /a di4erencia es que en lugar de enla*ar directamente con la base de datos 8como el Sql<ataSource9 o a una clase gen%rica 8como el "b+ect<ataSource9) este control est( dise:ado para enla*ar aun modelo de datos con /1N2. ;na de las venta+as de usar este control es que nivela la 4le-ibilidad de los "7,s basados en /1N2. No tenemos que de4inir m%todos para inserci.n5consulta5actuali*aci.n y borrado para el datasource 3 sino que a:adimos %ste control a nuestro modelo de datos) de4inimos con qu% entidades queremos que traba+e) y enla*amos cualquier control de $S'.NET para que traba+e con %l. 'or e+emplo) para tener un listado b(sico de los productos que use las entidades 'roduct con un modelo de datos /1N2 to S2/) s.lo tenemos que declarar un control Masp&linqdatasourceN en nuestra p(gina que enla*e a la clase dataconte-t de nuestro /1N2 to S2/) identi4icar las entidades 8por e+emplo& 'roducts9. W ya podemos enla*ar un >ridView con %l 8modi4icando su propiedad <ataSource1<9 para obtener un grid como el siguiente&

Sin tener que hacer nada m(s) podemos e+ecutar la p(gina y tener un listado de los productos con paginado y ordenaci.n. 'odemos a:adir los botones edit y delete en el grid y tener soporte autom(tico para ello. No tenemos que a:adir ningn m%todo) mapear ningn par(metro) ni escribir ningn c.digo para el control Masp&/inq<ataSourceN para tener todas estas operaciones. 0uando se hacen actuali*aciones) el "7, se asegurar( de que todas las reglas de negocio y de validaci.n que hemos a:adido se cumplan (ntes de guardar los datos.

Impo"tante: /a belle*a de /1N2 y /1N2 to S2/ es que obviamente no s.lo sirven para escenarios como el anterior 3 o para casos particulares para enla*ar controles de inter4aces de usuario como con el /inq<ataSource. 0omo ya hemos visto en los post anteriores) escribir c.digo con este "7, es muy limpio. Siempre podemos escribir c.digo personali*ado para nuestras inter4aces de usuario que traba+en directamente con el modelo de /1N2 to S2/ si queremos o cuando nos encontremos en un escenario en el que no se pueda usar Masp&linqdatasourceN

En los siguientes pasos veremos como montar la aplicaci.n que hemos descrito usando /1N2 to S2/ y el control Masp&/inq<ataSourceN !aso 1: DeBini" nuest"o modelo de datos Empe*aremos de4iniendo el modelo de datos que usaremos para representar la base de datos. Vimos c.mo de4inirlo en la segunda parte de estos artculos. $qu ten%is una captura de pantalla de las clases del modelo de datos creado con el dise:ador de /1N2 to S2/ de la base de datos !Northwind#&

Volveremos sobre nuestro modelo de datos en el paso J de este tutorial cuando a:adamos algunas reglas de validaci.n de negocio. 'ero para empe*ar usaremos el modelo de arriba. !aso #: C"eaci5n de un listado b>sico de p"oductos& Empe*aremos a crear la inter4a* con una p(gina $S'.NET con un control Masp&gridviewN con algun estilo css&

'odramos escribir c.digo para enla*ar program(ticamente nuestro modelo de datos al >ridView 8como hicimos en la tercera parte de la serie9) o podemos usar el control Masp&linqdatasourceN para enla*ar el >ridView al modelo de datos. VSBDDS nos permite enla*ar nuestro >ridView 8o cualquier control de servidor $S'.NET9 gr(4icamente a datos /1N2. 'ara hacerlo tenemos que pasar a la vista de dise:o) seleccionar el >ridView y elegir la opci.n !New <ata Source O# en !0hoose <ata Source#&

Esto nos mostrar( un cuadro de di(logo con una lista de 4uentes de datos disponibles. Seleccionamos la nueva opci.n !/1N2# y le damos el nombre que queramos&

El dise:ador del control Masp&linqdatasourceN nos mostrar( las clases <ata0onte-t de /1N2 to S2/ que hay disponibles 8incluyendo aquellas que est(n en las libreras que tengamos re4erenciadas9&

Seleccionaremos el modelo que creamos con el dise:ador de /1N2 to S2/. Seleccionaremos la tabla que queramos que sea la entidad principal con la que enla*ar el grid. En nuestro caso seleccionaremos la clase 'roducts. Tambi%n seleccionamos el boton !$dvanced# y habilitaremos las actuali*aciones y borrados para la 4uente de datos&

0uando hagamos clic en el bot.n !Finish#) VS BDDS declarar( un contorl Masp&linqdatasourceN en el .asp- y actuali*ar( el gridview para que use esta 4uente de datos. Tambi%n generar( las columnas necesarias para los di4erentes campos de la clase 'roduct&

$hora desplegamos el !smart tas # del grid view y le indicamos que queremos habilitar la paginaci.n) ordenado) edici.n y borrado&

'odemos pular FJ para e+ecutar la aplicaci.n) y veremos una p(gina con el listado de productos con paginaci.n y ordenado&

Tambi%n podemos pulsar los botones !edit# o !delete# en cada 4ila para actuali*ar los datos&

Si pasamos a la vista de c.digo de la p(gina) veremos las marcas que contiene. El control Masp&linqdatasourceN apunta a la clase <ata0onte-t) y a la tabla que le di+imos al principio. El >ridView tiene como 4uente de datos el control Masp&linqdatasourceN 8en el <atasource1<9 y le indica qu% columnas tienen que incluirse en el grid) cu(l es el te-to de la cabecera) y cual es la e-presi.n de ordenaci.n&

$hora tenemos lo b(sico para empe*ar a traba+ar con el comportamiento de esta inter4a* de usuario. !aso ': Limpiando las columnas& El grid tiene muchas columnas) y dos de ellas 8el Supplier1d y el 0ategory1<9 son claves a+enas) que no conviene mostrar al usuario. Eliminando columnas innecesarias Empe*aremos eliminando alguna de las columnas que no necesitamos. 'odemos hacer esto en la vista de c.digo8borrando la declaraci.n de Masp&bound4ieldN correspondiente9 o en la vista de dise:o 8haciendo clic en la columna y seleccionando la tarea !remove#9. 'or e+emplo) podemos eliminar la columna !2uantity'er;nit# y e+ectuar la aplicaci.n&

Si hemos usado el contorl Masp&"b+ect<ataSourceN y le hemos indicado e-plcitamente los par(metros de actuali*aci.n 8update9 a los m%todos de actuali*aci.n 8por de4ecto cuando usamos un <ataSet basado en Table$dapters9 una de las cosas que tenemos que hacer es cambiar la 4irma de los m%todos de actuali*aci.n del Table$dapter. 'or e+emplo& si eliminamos una columnan del grid) tenemos que modi4icar el Table$dapter para que soporte los m%todos de actuali*aci.n sin par(metros. 0on el control Masp&/inq<ataSourceN es que no tendramos que hacer este tipo de cambios. Simplemente borrando 8o a:adiendo9 una columna a la inter4a* de usuario y e+ecutamos la aplicaci.n =no hacen 4alta m(s cambios. 0on esto conseguimos que los cambios que se hagan en la inter4a* de usuario sean mucho m(s 4(ciles) y nos permite iteraciones m(s r(pidas en nuestra aplicaci.n. Limpiando las columnas SupplierId y %ategoryI& Vasta ahora estamos mostrando valores enteros de las claves a+enas en nuestro >ridView para los campos Supplier y 0ategory&

<esde el punto de vista del modelo de datos es correcto) pero no desde el punto de vista del usuario. /o que queremos hacer es mostrar el nombre de la categora y el nombre del proveedor) y mostrar una lista desplegable en modo edici.n para que podamos cambiar estas asociaciones de 4orma 4(cil. 'odemos cambiar el gridview para que muestre el nombre del proveedor y el de la categora en lugar del 1<) cambiando el Masp&?oundFieldN por un Masp&TemplateFieldN. W en este templateField a:adimos el contenido que queramos para personali*ar la vista de la columna. En el c.digo siguiente aprovecharemos la capacidad de /1N2 to S2/) que model. este campo como una propiedad. Es decir) posdemos enla*ar de 4orma 4(cil las propiedades Supplier.0ompanyName y 0ategory.0ategoryName al grid&

$hora e+ecutamos la aplicaci.n y tenedremos los valores de 0ategory y Supplier de la siguiente 4orma&

'ara tener una lista desplegable en estos dos campos en el modo edici.n) tenemos que a:adir dos controles Masp&/inq<ataSourceN a la p(gina. /os con4iguraremos para que se enlacen a las entidades 0ategories y Suppliers del modelo de datos creado por /1N2 to S2/&

$hora volvemos a la columnas Masp&TemplateFieldN que a:adimos antes y personali*aremos la parte de edici.n 8especi4icando un Edit1temTemplate9. <e 4orma que tendremos una lista desplegable en la vista edici.n) donde los valores disponibles se obtendr(n de las 4uentes de datos de categoras y proveedores) y enla*aremos doblemente el valor seleccionado al Supplier1d y 0ategory1< de las claves a+enas&

W ahora) cuando el usuario haga clic en el bot.n de edici.n) se mostrar( una lista con todos los proveedores disponibles&

W cuando salvemos los cambios se guardar( el valor seleccionado en la lista desplegable. 'aso (: )iltrando el listado de productos. ,(s que mostrar todos los productos de la base de datos) podemos actuali*ar la inter4a* de usuario para incluir una lista desplegable que permita al usuario 4iltrar los productos por una categora particular. 0omo ya a:adimos un Masp&/inq<ataSourceN enla*ada a las 0ategoras de nuesto modelo de /1N2 to S2/) s.lo tendremos que crear un nuevo control de lista desplegable y enla*arlo. 'or e+emplo&

0uando e+ecutemos la p(gina tendremos un 4iltro con todas las categoras al principio de la p(gina&

/o ltimo que queda es que cuando seleccionemos una categora se muestren los productos de dicha categora en el gridview. /o m(s 4acil es seleccionar la opci.n de !0on4igure <ataSource# en el smart tas del >ridView&

0on esto veremos el cuadro de dialogo para con4igurar el Masp&/inq<ataSourceN que usamos al principio del tutorial. Seleccionamos el bot.n !Khere# para a:adir un campo de 4iltro al datasource. 'odemos a:adir cualquier nmero de e-presiones) y declarativamente asignar los valores con los que 4iltrar 8por e+emplo& de una querystring) de valores de 4ormulario) de cualquier control en la p(gina) etc9.

Vamos a poner un 4iltro de productos por su 0ategory1<) y obtenemos el valor con el que 4iltrar de la lista desplegable que creamos antes&

0uando le damos a !Finish#) el contorl Masp&linqdatasourceN se actuali*ar( para re4le+ar los cambios de 4iltrado&

W cuando e+ecutamos la aplicaci.n el usuario ser( capa* de elegir una categora en la lista de 4iltrado y paginar) ordenar) editar y borrar los productos de una categora&

El control Masp&/inq<ataSourceN aplicar( las e-presiones /1N2 necesarias para que cuando se e+ecute contra el modelo de datos /1N2 to S2/ s.lo se obtengan los datos necesarios de la base de datos 8por e+emplo& en el grid anterior s.lo obtendremos I 4ilas con los productos de la categora 0on4ection9. Tambi%n podemos gestionar nosotros el evento Selecting si queremos escribir e-presiones /1N2 personali*adas. 'aso *: "#adir reglas de +alidaci,n de negocio 0omo ya vimos en la cuarta parte de esta serie de post) cuando de4inimos modelos de datos con /1N2 to S2/ tendremos un con+unto de esquemas de validaci.n por de4ecto 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 a+ena en una 4ila que no e-ista) el modelo lan*ar( un error y se asegurar( de que la integrar de la base de datos se mantiene. El esquema b(sico de validaci.n es s.lo el primer paso) y es muy raro en la mayora de aplicaciones reales. Normalmente necesitaremos a:adir reglas adicionales a nuestro modelo de datos. $4ortunadamente con /1N2 to S2/ podemos a:adir estas reglas de 4orma muy 4(cil 8para m(s detalles sobre este tema) leed la cuarta parte de esta serie de post9. E-emplo de escenario con reglas de +alidaci,n 'or e+emplo) supongamos una regla b(sica que queramos re4or*ar. 2ueremos que un usuario de nuestra aplicaci.n no pueda interrumpir un producto mientras haya unidades pedidas&

Si un usuario intenta guardar la 4ila anterior) queremos prevenir que ese cambio se guarde en la base de datos y que genere un error para que el usuario lo arregle. "#adiendo una regla de +alidaci,n al modelo de datos. El sitio incorrecto para a:adir este tipo de validaci.n es en la capa de presentaci.n. $:adirlo en esta capa implica que esta regla ser( s.lo v(lida en un lugar concreto) y no ser( autom(tico en cualquier parte de la aplicaci.n. <istribuir la l.gica de negocio en la capa de presentaci.n tambi%n har( que nuestra vida sea realmente penosa a medida que nuestra aplicaci.n cre*ca 3 ya que cualquier cambio5actuali*aci.n en nuestro negocio hara necesarios cambios de codigo en todas partes. El lugar correcto para este tipo de validaci.n es en las clases del modelo de datos de /1N2 to S2/. 0omo ya vimos en la cuarta parte de esta serie) todas las clases se generan por el dise:ador de /1N2 to S2/ como clases parciales 3 con lo que podemos a:adir m%todos5eventos5propiedades 4(cilmente. El modelo de /1N2 to S2/ e+ectuar( los m%todos de validaci.n que podemos implementar. 'or e+emplo) 'odemos a:adir una clase parcial 'roduct a nuestro proyecto que implemente el m%todo parcial "nValidate89 que /1N2 to S2/ llama antes de guardar las entidades de 'roduct. En este m%todo podemos a:adir la siguiente regla de negocio para segurarnos que los productos no pueden tener un 7eorder /evel si el producto es discontinued&

;na ve* que a:adimos la clase anterior al proyecto /1N2 to S2/) la regla anterior se comprobar( cada ve* que alguien use nuestro modelo de datos e intente modi4icar la base de datos. Esto se hace tanto para los productos e-istentes que se vayan a actuali*ar como para los que se vayan a a:adir nuevos. 0omo el Masp&/inq<$taSourceN traba+a contra nuestro modelo de datos) cada actuali*aci.n5inserci.n5borrado pasar( por esta regla de validaci.n antes de guardar los cambios. No necesitamos hacer nada m(s en la capa de presentaci.n para que se cumpla esta regla 3 se comprobar( cada ve* que se use nuestro modelo de datos. "#adir un mane-ador de errores en la capa de presentaci,n. 'or de4ecto si un usuario usa nuestro >ridView para meter una combinaci.n no v(lida de ;nit"n"rder5<iscontinued) nuestro modelo /1N2 to S2/ lan*ar( una e-cepci.n. El Masp&/inq<ataSourceN capturar( la e-cepci.n y nos proporciona un evento que podemos usar para controlarlo. Si nadie usa el evento) el contol >ridView 8u otro9 enla*ado al Masp&/inq<ataSourceN capturar( el error y proveer( un evento para controlarlo. Si nadie controla el error ser( pasado al mane+ador d ela p(gina) y si nadie lo controla) se le pasar( al evento $pplicationLError89 en el archivo >lobal.asa-. /os desarrolladores pueden hacer esto en cualquier paso del camino para a:adir la l.gica de errores que queramos en la capa de presentaci.n. 'ara la aplicaci.n que estamos viendo) seguramente el me+or lugar para controlar cualquier error de actuali*aci.n sea en el vento row;pdated del gridView. Este evento se e+ectuar( cada ve* que se actuali*e en nuestro datasource) y podemos ver los detalles de la e-cepci.n si 4alla la actuali*aci.n. 'odemos a:adir el siguiente c.digo para comprobar si ha ocurrido un error) y mostrar un error adecuado en caso de que ocurra&

No hemos tenido que a:adir ninguna validaci.n l.gica en nuestra inter4a* de usuario. En lugar de eso) estamos obteniendo el error que lan*amos en nuestra l.gica de negocio y la estamos usando para mostrar un mensa+e adecuado al usuario 8Estamos mostrando un error m(s gen%rico9.

Tambi%n le estamos indicando que queramos que el >ridView se mantenga en el modo edici.n cuando ocurra un error 3 de 4orma que podemos evitar que el usuario pierda los cambios que estaba haciendo) y modi4icar los valores y darle a !update# otra ve* e intentar guardarlo. 'odemos a:adir un control Masp&literalN en el !Error,essage# en cualquier parte de la pagina que queramos para controlar donde queremos que se muestre el error&

W ahora cuando intentemos actuali*ar un producto con valores erroneos veremos un mensa+e de error que indica c.mo arreglarlo&

/o bueno de esto es que podemos a:adir o cambiar las reglas de negocio sin tener que cambiar nada en la capa de presentaci.n. /as reglas de validaci.n) y sus mensa+es correspondientes) pueden centrali*arse en un lugar en concreto del modelo de datos y se aplicar(n en todas partes. 2esumen El control Masp&/inq<ataSourceN nos da una 4orma 4(cil de enla*ar controles de $S'.NET a nuestro modelo de /1N2 to S2/. 'ermite obtener5actuali*ar5insertar5borrar datos del modelo de datos. En nuestra aplicaci.n hemos usado el "7, /1N2 to S2/ para crear un modelo limpio) orientado a ob+etos. $:adimos tres contorles $S'.NET a la p(gina 8un gridView) una lista desplegable) y un errormessage literal9) y hemos a:adido tres contorles Masp&/inq<ataSourceN para enla*ar a 'roduct) 0ategory y 'roveedores&

Escribimos J lneas de validaci.n l.gica y AA lineas para la gesti.n de errores. El resultado 4inal es una aplicaci.n web simple que permite a los usuarios 4iltrar los productos por su categora) ordenar y paginar e4icientemente dichos productos) editar los productos y guardarlos 8con nuestra reglas de negocio9) y borrar productos del sistema 8tambi%n con nuestra l.gica de negocio9.

LINQ to SQL (Parte ( ) tener datos con *rocedimientos almacenados)


'ublicado en .NET) $S' .NET) /1N2) /1N2 to S2/) Scott >uthriP) S2/ a I&D[ pm por Fuanma

En las ltimas semanas he escrito una serie de post sobre /1N2 to S2/. Es un "7, integrado en .NET I.J) y nos permite modelar bases de datos relacionales con clases de .NET. 'odemos usar e-presiones /1N2 para consultar a la base de datos) actualia*arla) insertar y borrar datos. $qu ten%is los enlaces a los otros post&

'arte A& 1ntroducci.n a /1N2 to S2/ 'arte B& <e4iniendo el modelo de datos. 'arte I& 0onsultando la base de datos 'arte Q& $ctuali*ando la base de datos. 'arte J& Enla*ar controles de inter4a* de usuario con el $S'&/inq<atSource

En estos posts vimos c.mo usar e-presiones /1N2 para obtener program(ticamente datos de la base de datos. En el post de hoy veremos c.mo podemos usar los procedimientos almacenados 8S'7"0s9 y las 4unciones de4inidas por el usuario 8;<Fs9 con nuestro modelo /1N2 to S2/. El post de hoy veremos el caso de los S'7"0s para consultar y obtener datos de la base de datos. En el siguiente post de esta serie veremos c.mo actuali*ar5insertar5borrar datos con S'7"0s. S!21C o no S!21C? Esa es la cuesti5n /a pregunta sobre cuando usar el S2/ din(mico generado por un "7, en lugar de procedimientos almacenados creando una capa de datos es causa de debates muy acalorados entre desarrolladores) arquitectos y <?$s. ,ucha gente m(s lista que yo ha escrito sobre esto) as que no me decantar% ni por un lado ni por otro. /1N2 to S2/ es muy 4le-ible) y puede usare para crear un modelo de datos cuyos ob+etos sean independientes del esquema de la base de datos) y puedeencapsular l.gica de negocio y reglas de validaci.n que 4uncionan tanto si se usa S2/ generado din(micamente o a trav%s de S'7"0s. En el tercer post de esta serie) hablamos sobre c.mo podemos escribir e-presiones /1N2 contra el modelo de /1N2 to S2/ como el siguiente c.digo&

0uando escribimos e-presiones /1N2 como esta) /1N2 to S2/ e+ecutar( el S2/ din(mico necesario para obtener los ob+etos de 'roduct que cumplan las restricciones. 0omo aprenderemos en este post) tambi%n podemos mapear S'7"0s en la base de datos con la clase <ata0onte-t generada por /1N2 to S2/) que nos permitir( obtener los mismo ob+etos de 'roduct llamando a un procedimiento almacenado&

Esta habilidad de poder usar tanto S2/ din(mico como S'7"0s con una capa de datos limpia es muy til y nos permite una gran 4le-ibilidad en nuestros proyectos.

!asos pa"a mapea" , llama" a S!21C con LINQ to SQL En el segundo post de la serie vimos c.mo usar el dise:ador /1N2 to S2/ para crear el siguiente modelo de clases&

Fi+aos en las dos partes del dise:ador. /a de la i*quierda nos permite de4inir el modelo de datos que mapeara nuestra base de datos. El de la derecha nos permite mapear S'7"0s 8y ;<Fs9 en nuestro ob+eto <ata0onte-t) que podemos usar en lugar del S2/ din(mico para traba+ar con los ob+etos de nuestro modelo de datos. C5mo mapea" un S!21C en un DataContext de LINQ to SQL

'ara mapear S'7"0s en la clase <ata0onte-t) vamos primero al e-plorador de servidores de VS BDDS y miramos a los S'7"0s de nuestra base de datos&

Vaciendo doble clic en cualquier S'7"0 se abrir( para edici.n y podremos ver el c.digo. 'or e+emplo) aqu ten%is el S'7"0 !0ust"rderVist# de la base de datos Northwind&

'ara mapearlo en nuestra clase <ata0onte-t) lo arrastarmos y soltamos desde el e-plorador de servidores al dise:ador de /1N2 to S2/. $utom(ticamente se crear( un nuevo m%todo en la clase <ata0onte-t&

'or de4ecto el nombre del nuevo m%todo en la clase <ata0onte-t ser( el mismo que el del S'7"0) y el tipo de datos devueltos se crear( autom(ticamente con el siguiente patron& !\NombredelS'7"0]7esult#. 'or e+emplo& el S'7"0 de arriba devolver( una secuencia de ob+etos del tipo !0ust"rderVist7esult#. 'odemos cambiar el nombre del m%todo seleccion(ndolo en el dise:ador y cambiarlo en la ventana de propiedades. Como llama" a un nue)o S!21C mapeado& ;na ve* que hemos seguido los pasos para mapear el S'7"0 en la clase <ata0onte-t) es muy 4(cil de usar. Todo lo que tenemos que hacer es llamarlo para obtener los resultados 4uertemente tipados& En V?&

En 0@&

$dem(s de poder hacer un bucle sobre los resultados) tambi%n podemos enla*ar los resultados con cualquier control para mostrarlos. 'or e+emplo) el siguiente c.digo enla*a los resultados del S'7"0 a un control Masp&gridviewN

0on lo que mostramos la historia de productos de un cliente&

Mapeando los tipos "esultado de los S!21C del modelo de datos En el S'7"0 !0ust"rderVist# devolva una secuencia de ob+etos con dos columnas& el nombre del producto y el numero total de pedidos que el cliente ha hecho de ese producto. El dise:ador /1N2 to S2/ de4ini. la clase !0ust"rderVist7esult# para representar los resultados. Tambi%n podemos decidir mapear los resultados del S'7"0 a una clase de nuestro modelo de datos 8por e+emplo& a una entidad 'roduct o "rder9. 'or e+emplo) tenemos el S'7"0 !>et'roducts?y0ategory# en nuestra base de datos que devuelve la siguiente in4ormaci.n&

0omo (ntes podemos crear un m%todo !>et'roducts?y0ategory# en la clase <ata0onte-t que llama a este S'7"0 arrastr(ndolo al dise:ador de /1N2 to S2/. ,(s que simplemente arrastrar el S'7"0 al dise:ador) lo arrastraremos encima de la clase !'roduct#&

0on esto) el m%todo !>et'roducts?y0ategory# devolver( una secuencia de ob+etos !'roduct#&

/1N2 to S2/ seguir( los cambios hechos a los ob+etos que se devuelvan como si 4uesen ob+etos 'roducts obtenidos a partir de e-presiones /1N2. 0uando llamemos al m%todo !Submit0hanges89# todos los cambios hechos a esos ob+etos se guardar(n en la base de datos. 'or e+emplo) con el siguiente c.digo obtenemos y cambiamos el precio de todos los productos de una categora aument(ndolo en un TD U&

'ara entender c.mo 4unciona el m%todo Submit0hanges89 y el seguimiento que se hace de los cambios) y ver c.mo podemos a:adir l.gica de negocio a nuestro modelo de datos leed el cuarto post de esta serie. En el pr.-imo post de esta serie veremos tambi%n c.mo cambiar el S2/ generado cuando insertamos5actuali*amos5borramos datos con S'7"0s personali*ados. /o bueno de todo esto es que el c.digo anterior no habr( que cambiarlo si hemos con4igurado la clase <ata0onte-t para que use S'7"0s para las actuali*aciones =

Manejando "esultados m3ltiples desde S!21Cs 0uando un procedimiento almacenado puede devolver varios tipos de datos) el tipo de resultado del S'7"0 en la clase <ata0onte-t no puede ser 4uertemente tipado. 'or e+emplo) imaginemos el siguiente S'7"0 que puede devolver un producto o un pedido dependiendo del par(metro de entrada&

/1N2 to S2/ permite crear m%todos au-iliares para devolver 'roduct o "rder a:adiendo una clase parcial !Northwind<ata0onte-t# al proyecto que de4ina un m%todo 8que en este caso llamaremos !VariablesShapeSample#9 que invoca al S'7"0 y devuelve un ob+eto 1,ultiple7esult& V?&

0@&

;na ve* que a:adimos este m%todo al proyecto podemos llamarlo y convetir los resultados tanto a una secuencia de 'roduct como de "rder& V?&

0@&

Sopo"te de Bunciones deBinidas po" el usua"io 46DCs $dem(s de S'7"0S) /1N2 to S2/ tambi%n soporta tanto 4unciones de usuario de valores y de tablas de valores 8;<Fs9. ;na ve* que a:adimos un m%todo a la clase <ata0onte-t) podemos usar estas 4unciones en nuestras consultas /1N2. 'or e+emplo) veamos la 4unci.n simple !,y;pperFunction#&

'odemos arrastrar y soltar desde el e-plorador de servidores al dise:ador de /1N2 to S2/ para a:adirlo como un m%todo a nuestro <ata0onte-t&

/uego podemos usar esta 4unci.n ;<F en e-presiones /1N2 cuando escribimos consultas contra nuestro modelo /1N2 to S2/& V?&

0@&

Si usamos el visuali*ador de debug de /1N2 to S2/ del que ya hablamos aqu)podemos ver c.mo /1N2 to S2/ trans4orma la e-presi.n anterior en una S2/ que e+ecutar( el ;<F en la base de datos en tiempo de e+ecuci.n&

2esumen /1N2 to S2/ soporta poder usar procedimientos almacenados y ;<Fs contra la base de datos y los integra en nuestro modelo de datos. En este post hemos visto c.mo podemos usar S'7"0s para obtener datos y pasarlo entre nuestras clases del modelo. En el pr.-imo post veremos c.mo podemos usar S'7"0S para sobreescribir la l.gica de actuali*aci.n5inserci.n5borrado cuando llamamos a Submit0hanges89 en el <ata0onte-t para guardar los cambios.

LINQ to SLQ (Parte + "ctuali#ando la ase de datos con *rocedimientos almacenados)


'ublicado en .NET) $S' .NET) /1N2) /1N2 to S2/) Scott >uthriP) S2/) Visual Studio a AB&JA am por Fuanma

En las ltimas semanas he escrito una serie de post sobre /1N2 to S2/. Es un "7, integrado en .NET I.J) y nos permite modelar bases de datos relacionales con clases de .NET. 'odemos usar e-presiones /1N2 para consultar a la base de datos) actualia*arla) insertar y borrar datos. $qu ten%is los enlaces a los otros post&

'arte A& 1ntroducci.n a /1N2 to S2/ 'arte B& <e4iniendo el modelo de datos. 'arte I& 0onsultando la base de datos 'arte Q& $ctuali*ando la base de datos. 'arte J& Enla*ar controles de inter4a* de usuario con el $S'&/inq<atSource 'arte E& "btener datos con procedimientos almacenados.

En la se-ta parte vimos c.mo podemos usar procedimientos almacenados 8S'7"0s9 y 4unciones de4inidas por el usuario 8;<Fs9 para consultar la base de datos con el modelo de datos de /1N2 to S2/. En el post de hoy veremos c.mo podemos usar los S'7"0s para actuali*ar5insertar5borrar datos de nuestra base de datos.

'ara ayudar a entender esto empe*aremos costruyendo una capa de datos para la base de datos de e+emplo Northwind& !aso 1: C"ea" nuest"a capa de acceso a datos 4sin S!21Cs En la segunda parte de esta serie vimos c.mo usar el dise:ador de /1N2 to S2/ de VS BDDS para crear el siguiente modelo de clases&

$(adiendo "e*las de )alidaci5n a nuest"o modelo de clases& <espu%s de de4inir nuestro modelo querremos a:adir reglas de validaci.n a nuestro modelo de datos. 'odemos hacer esto a:adiendo clases parciales a nuestro proyecto y a:adir las reglas de validaci.n en esas clases 8vimos c.mo hacer esto en la cuarta parte de esta serie9.

'or e+emplo) podemos a:adir la l.gica necesaria para asegurarnos de que el nmero de tel%4ono de los clientes siguen un patr.n v(lido) y otra para asegurarnos de que la 4echa de entrega 87equierd<ate9 es posterior a la 4echa actual del pedido 8"rder<ate9. ;na ve* que hemos de4inido las clases parciales) estos m%todos de validaci.n se e+ecutar(n cada ve* que escribamos c.digo para actuali*ar nuestros ob+etos de datos de nuestra aplicaci.n& V?&

0@&

$(adi" un mtodo de a,uda DetCustome"4 a nuest"o DataContext ;na ve* que hemos creado nuestro modelo de clases) y que le hemos a:adido reglas de validaci.n) podemos consultar e interactuar con los datos. 'odemos hacer esto escribiendo e-presiones /1N2 sobre nuestro modelo de clases 8vimos c.mo hacer esto en la tercera parte de esta serie9. Tambi%n podemos mapear S'7"0s en nuestro <ata0onte-t 8esto lo vimos en la se-ta parte de la serie9. 0uando creamos una capa de datos con /1N2 to S2/ normalmente querremos encapsular consultas comunes de /1N2 8o S'7"0s9 en m%todos au-iliares que a:adiremos a la clase <ata0onte-t. Esto lo conseguimos a:adiendo una clase parcial a nuestro proyecto. 'or e+emplo) podemos a:adir un m%todo llamado !>et0ustomer89# que nos permita buscar y obtener ob+etos 0ustomer de la base de datos a partir del valor 0ustomer1<& V?&

0@&

!aso #: 6sando nuest"a capa de datos 4se*uimos sin S!21Cs Wa tenemos una capa de datos que encapsula nuestro modelo de datos) integra reglas de validaci.n) y nos permite consultar) actuali*ar) insertar y borrar datos. Veamos ahora un escenario simple us(ndolo para obtener un ob+eto customer e-istente) actuali*amos el 0ontactName y el 'honeNumber) y creamos un nuevo ob+eto "rder para asociarlos. El siguiente c.digo hace todo eso en una sola transacci.n. /1N2 to S2/ se asegura de que las reglas de validaci.n se cumplen (ntes de guardar nada en la base de datos&

V?&

0@&

/1N2 to S2/ monitori*a todas las modi4icaciones de los ob+etos que hemos obtenido de la base de datos) y guarda los ob+etos que a:adimos. 0uando llamamos al m%todo <ata0onte-t.Submit0hanges89) /1N2 to S2/ comprueba las reglas que hemos establecido) y genera autom(ticamente la S2/ que actuali*ar( el registro de 0ustomer e insertar( un nuevo registro en la tabla "rders 6n momento E !ensaba =ue este post iba sob"e S!21Cs Si an estais leyendo) os preguntar%is d.nde est(n los S'7"0s en este post. G'orque os estoy mostrando el c.digo de arriba que hace que se genere una S2/ din(micaH G'or qu% no os he ense:ado c.mo llamar a un S'7"0 para hacer las inserciones5actuali*aciones5borrados todavaH /a ra*.n es que el modelo de programaci,n de LINQ to SQL tanto para traba-ar con ob-etos modelados mediante S'.O% es e/actamente el mismo que con SQL din0mico. /a manera en que a:adimos validaci.n l.gica es e-actamente igual 8as que todas las reglas que hemos a:adido a nuestro modelo de datos se aplicar(n tambi%n si usamos S'7"0s9. El c.digo anterior que hemos usado para obtener un cliente) actuali*arlo y a:adir un nuevo pedido es exactamente i*ual tanto si usamos S2/ din(mico como si usamos S'7"0s. Esta simetra en el modelo de programaci.n es muy potente ya que no tenemos que aprender dos maneras di4erentes de hacer las cosas) ni tenemos que decidir al principio del proyecto qu% t%cnica usar) si S'7"0 o no. 'odemos empe*ar usando el S2/ din(mico que nos da /1N2 to S2/ para las consultas) inserciones) actuali*aciones y borrados. 'odemos a:adir reglas de validaci.n a nuestro modelo. W luego podemos actuali*ar el modelo de datos para usar S'7"0s 3 o no. El c.digo y los test que escribamos contra las clases del modelo de datos ser(n e-(ctamente iguales. <e ahora en adelante veremos c.mo podemos actuali*ar nuestro modelo de datos usando S'7"0s para actuali*ar5insertar5borrar 3 mientras seguimos usando las mismas reglas de validaci.n y traba+aremos con los mismos c.digos anteriores. C5mo usa" S!21Cs en inse"ciones? actuali%aciones , bo""ados 'odemos modi4icar la capa de datos que estamos construyendo para que use S'7"0s) en lugar de S2/ din(mico de dos maneras& A. ;sando el dise:ador de /1N2 to S2/ para con4igurar gr(4icamente la e+ecuci.n de los S'7"0s en las di4erentes operaciones o

B. $:adir una clase parcial Northwind<ata0onte-t a nuestro proyecto) y entonces implementar los m%todos
necesarios para la inserci.n) borrado y actuali*aci.n. 8por e+emplo& 1nsert"rder) ;pdate"rder) <elete"rder9 que ser(n llamados cuando se reali*e alguna de las operaciones asociadas. Estos m%todos parciales ser(n pasados a las instancias del modelo de datos que queramos actuali*ar) y podemos e+ecutar tanto S'7"0 como c.digo S2/ para guardarlo.

0uando usemos la primera apro-imaci.n para con4igurar gr(4icamente los S'7"0s que llamaremos) por deba+o se est( generando el mismo c.digo 8en clases parciales que crea %l solo9 que escribiramos si elegimos la segunda opci.n. En general os recomiendo que us%is el dise:ador de /1N2 to S2/ para con4igurar los S'7"0s en el TDU de los casos 3 y crear las llamadas personali*adas a procedimientos almacenados en escenarios m(s avan*ados. !aso ': Face" ot"as inse"ciones con un S!21C Empe*aremos cambiando nuestro modelo de datos para que use S'7"0s con el ob+eto "rder. 'rimero nos vamos a la ventana de !E-plorador de Servidores# 8Server E-plorer9 de Visual Studio) e-pandimos el nodo !Stored 'rocedures# de nuestra base de datos) hacemos clic con el bot.n derecho y elegimos la opci.n !$dd New Stored 'rocedure#&

0reamos el nuevo procedimiento almacenado que llamaremos !1nsert"rder# que a:ade una nueva 4ila order a la tabla "rders&

Fi+(os que hemos de4inido el par(metro !"rder1d# como un par(metro de salida. ESto es debido a que la columna "rder1< es una columna identidad que se autoincrementa cada ve* que se a:ade un nuevo registro. 2uien llame a este S'7"0 dever( pasarle un valor null en ese par(metro 3 y el S'7"0 devolver( en ese par(metro el nuevo valor "rder1< 8llamando a la 4unci.n S0"'EL1<ENT1TW89 al 4inal del S'7"09. <espu%s de crear el S'7"0 abrimos el dise:ador de /1N2 to S2/. <e la misma 4orma que vimos en la se-ta parte de esta serie) podemos arrastrar y soltar S'7"0s desde la ventana !server e-plorer# al dise:ador. Esto es lo que haremos con el nuevo S'7"0 que acabamos de crear&

El ltimo paso ser( decirle a nuestra capa de datos que use el S'7"0 1nsert"rder cuano inserter un nuevo ob+eto "rder en la base de datos. Esto lo hacemos seleccionando la clase !"rder# del dise:ador /1N2 to S2/) y en las propiedades clicamos el bot.n !O# del m%todo 1nsert&

Vacemos clic en el bot.n !O# y aparecer( una ventana que nos permite personali*ar las operaciones de inserci.n&

Fi+aos c.mo el modo po de4ecto 8!;se 7untime#9 est( con4igurado para usar /1N2 to S2/ como generador din(mico de las S2/. 'ara cambiarlo seleccionamos el radio buton !0ustomi*e# y seleccionamos el S'7"0 1nsert"rder de la lista de S'7"0S disponibles&

El dise:ador de /1N2 to S2/ calcular( una lista de parametros para el S'7"0 que hemos seleccionado) permiti%ndonos mapear las propiedades de nuestra clase "rder a los par(metros del S'7"0 1nsert"rder. 'or de4ecto seleccionar( el que m(s se pare*ca en el nombre. 'odemos cambiarlo si queremos. ;na ve* que cliquemos en "C est( listo. $hora cada ve* que a:adamos un nuevo pedido a nuestro <ata0onte-t e invoquemos al m%todo Submit0hanges89) se e+ecutar( el S'7"0 1nsert"rder. 1mportante& $unque estemos usando S'7"0 para la persistencia) el m%todo parcial !"nValidate89# que creamos 8en la primer parte de esta serie9 para encapsular las reglas de validaci.n para los pedidos seguir(n e+ecut(ndose antes de reali*ar cualquier cambio. Es decir) tenemos una 4orma limpia de encapsular la l.gica de negocio y las reglas de validaci.n en nuestros modelos de datos) y podemos reutili*arlos tanto si usamos S2/ o S'7"0S. !aso -: $ctuali%ando los clientes con S!21Cs& $hora vamos a modi4icar el ob+eto 0ustomer para mane+ar las actuali*aciones con un S'7"0. Empe*amos creando el S'7"0 !;pdate0ustomer#&

Fi+aos que adem(s de pasar el par(metro ^0ustomer1<) tambi%n tenemos un par(metro ^"riginalL0ustomer1<. /a columna 0ustomer1< de la tabla 0ustomers no es un campo autoincremental) y puede modi4icarse cuando hagamos una actuali*aci.n. 'or tanto necesitamos ser capaces de decirle al S'7"0 cual es el 0ustomer1< original y el nuevo 0ustomer1<. Vamos a ver c.mo mapeamos esto con el dise:ador de /1N2 to S2/. Ver%is que estamos pasando un par(metro llamado ^Version 8que es una marca de tiempo9 al S'7"0. Es una nueva columna que he a:adido a la tabla 0ustomers para ayudarme a controlar la concurrencia optimista. Veremos en m(s detalle este tema en otro post de esta serie 3 pero en resumen es que /1N2 to S2/ soporta completamente la concurrencia optimista) y nos permite usar tanto una marca de tiempo o usar valores original5nuevo para detectar si ha habido algn cambio por parte de otro usuario (ntes de guardar los datos. 'ara este e+emplo usaremos una marca de tiempo ya que hace que el c.digo sea mucho m(s claro. ;na ve* que tenemos nuestro S'7"0) lo arrastramos y soltamos al dise:ador /1N2 to S2/ para a:adirlo como m%todo a nuestro <ata0onte-t. Seleccionamos la clase 0ustomer y hacemos clic en el bot.n !O# de la propiedad ;pdate&

Seleccionamos el radio button !0ustomi*e# y seleccionamos el S'7"0 ;pdate0ustomer&

0uando mapeamos las propiedades de los ob+etos 0ustomer con los par(metros del S'7"0) veremos que tenemos que decidir si poner la propiedad !current# en el ob+eto de datos) o si poner el valor original que estaba en la base de datos antes de obtener el ob+eto. 'or e+emplo) tendremos que asegurarnos de que mapeamos el valor !current# de la propiedad 0ustomer1< en el par(metro ^0ustomer1<) y el valor original en el par(metro ^originalLcustomer1<. 0uando hacemos clic en "C ya esta terminado. $hora cuando actuali*emos cualquier cliente y llamemos a Submit0hanges89 se e+ectuar( el S'7"0 ;pdate0ustomer en lugar de e+ecutarse un S2/ din(mico. 1mportante& $unque ahora estemos usando S'7"0) el m%todo parcial !"n'hone0hanging89# de la clase 0ustomer 8que creamos en el primer post de esta serie9 para validar los nmeros de tel%4ono se seguir( e+ecutando de la misma manera (ntes de que se guarden los cambios. Tenemos de esta 4orma una 4orma limpia de encapsular reglas de negocio y validaci.n a nuestros modelos de datos) y podemos reutili*arlos tanto si usamos S2/ din(mico o S'7"0s. !aso /: 6sando el modelo de datos ot"a )e% 4esta )e% con S!21Cs $hora que ya tenemos con4igurada nuestra capa de datos para usar S'"0s en lugar de S2/ din(mico) podemos e+ecutar el mismo c.digo que vimos en el paso B&

$hora las actuali*acion del ob+eto 0ustomer) y la inserci.n del ob+eto "7der) se est(n e+ecutando a trav%s de S'7"0s en lugar de S2/ din(mico. /a l.gica de validaci.n que de4inimos se siguen e+ecutando como antes) y el c5di*o si*ue siendo exactamente el mismo& $puntes a)an%ados cuando usamos S!21Cs

Veamos unas cuantas recomendaciones tiles para escenarios con S'7"0 m(s avan*ados con /1N2 to S2/ 1so de par0metros de salida En casos de inserci.n 8'aso I9 hemos visto c.mo podemos devolver el nuevo valor "rder1< 8que es un valor identidad y autoincremental de la tabla "rders9 usando un par(metro de salida en el S'7"0. No estamos limitados a devolver s.lo valores de columnas identidad con S'7"0s y /1N2 to S2/ 3 en realidad podemos actuali*ar y devolver cualquier par(metro. 'odemos usarlo tanto para insetar como para actuali*ar. /1N2 to S2/ tomar( el valor resultado y actuali*ar( la propiedad asociada en el modelo de dato sin que tengamos que hacer ninguna consulta e-tra para re4rescarlo o calcularlo de nuevo. 2Que pasa si el S'.O% da un error3 Si el S'7"0 da un error mientras inserta) actuali*a o borra un dato) /1N2 to S2/ cancelar( y deshar( la transacci.n de todos los cambios asociados a la llamada Submit0hanges89. <e manera que nos aseguramos la consistencia de los datos. 2'odemos escribir c,digo en lugar de usar el dise#ador para llamar a un S'.O%3 0omo ya coment% al principio) podemos usar tanto el dise:ador de /1N2 to S2/ para mapear las operaciones con S'7"0 o podemos a:adir m%todos parciales a la clase <ata0onte-t program(ticamente e invocarlos nosotros mismo. $qu ten%is un e+emplo del c.digo que deberamos escribir para sobreescribir el m%todo ;pdate0ustomer de la clase Northwind<ata0onte-t&

Este c.digo es el que 4u% generado con el dise:ador de /1N2 to S2/ cuando lo usamos para mapear el S'7"0 y asociarlo a la operaci.n de ;pdate del ob+eto 0ustomer. 'odemos usarlo como un punto de partida y a:adir alguna l.gica adicional para hacerlo m(s personali*ado 8por e+emplo& usar el valor de retorno del S'7"0 para lan*ar e-cepciones personali*adas9. 2esumen /1N2 to S2/ es un "7, muy 4le-ible. Nos permite escribir c.digo limpio orientado a ob+etos para obtener) acutali*ar e insertar datos.

/o me+or de todo es que nos permite dise:ar una capa de datos realmente limpia e independiente de c.mo se guardan y cargan los datos de la base de datos. 'odemos usar S2/ din(mico o S'7"0s para esas operaciones. /o me+or es que el c.digo que use nuestra capa de datos) y todas las reglas de negocio asociadas) ser(n las mismas sin importar que m%todo de persistencia estemos usando.

LINQ to SQL (Parte , %-ecutar consultas SQL *ersonali#adas)


'ublicado en .NET) $S' .NET) /1N2) /1N2 to S2/) Scott >uthriP) S2/) Visual Studio a T&QS pm por Fuanma

En las ltimas semanas he escrito una serie de post sobre /1N2 to S2/. /1N2 to S2/ es un "7, que viene con .NET I.J) y nos permite modelar bases de datos relacionales en clases. 'odemos usar e-presiones /1N2 para consultar la base de datos y tambi%n para actuali*ar) insertar y borrar datos. $qu teneis los enlaces a los di4erentes post de la serie&

'arte A& 1ntroducci.n a /1N2 to S2/ 'arte B& <e4iniendo el modelo de datos. 'arte I& 0onsultando la base de datos 'arte Q& $ctuali*ando la base de datos. 'arte J& Enla*ar controles de inter4a* de usuario con el $S'&/inq<atSource 'arte E& "btener datos con procedimientos almacenados. 'arte [& $ctuali*ando la base de datos con procedimientos almacenados.

En los dos ltimos post vismo c.mo podemos usar los procedimientos almacenados de nuestra base de datos para consultar) insertar) actuali*ar y borrar datos con el modelo de /1N2 to S2/. ;na pregunta que me han hecho mucho desde que he escrito estos post es& Gque pasa si quiero control total sobre las consultas S2/ que usa /1N2 to S2/ 3 pero no quiero usar S'7"0s para hacerloH En el post de hoy veremos eso 3 y veremos c.mo podemos usar e-presiones S2/ personali*adas para que /1N2 to S2/ las use en lugar de las que generara %l. 6so de exp"esiones LINQ con LINQ to SQL& Supongamos que hemos usado el dise:ador de /1N2 to S2/ de VS BDDS para modelar un con+unto de clases a partir de la base de datos Northwind 8esto lo vimos en el segundo post de la serie9&

En el tercer post vimos c.mo podemos usar /1N2 con las nuevas caractersticas de V? y 0@ para consultar el modelo de clases y devolver un con+unto de ob+etos que representan las 4ilas y columnas de la base de datos. 'or e+emplo) podemos a:adir un m%todo a la clase <ata0onte-t !>et'roducts?y0ategory# que usa una consulta /1N2 para devolver ob+etos de 'roducts de la base de datos& V?&

c@&

;na ve* de4inido nuestro m%todo de /1N2) podemos escribir el siguiente c.digo para obtener productos e iterar sobre ellos& V?&

0uando se evala la e-presi.n /1N2 del m%todo !>et'roducts?y0ategory#) el "7, /1N2 to S2/ e+ectuar( un S2/ din(mico para obtener los datos de la tabla 'roduct para crear los ob+etos 'roduct. 'odeis usar el Visuali*ador de <ebug de /1N2 to S2/ para ver en el debugger cu(l es la e-presi.n /1N2 que se e+ectuar(. 6so de consultas SQL pe"sonali%adas con LINQ to SQL En el e+emplo de arriba no tenemos que escribir ningn c.digo S2/ para consultar y obtener ob+etos 'roduct 4uertemente tipados. /1N2 to S2/ traduce la e-presi.n /1N2 a S2/ por nosotros. G'ero que pasa si queremos un control total sobre el S2/ que se est( e+ecutando en nuestra base de datos) y no queremos que /1N2 to S2/ lo haga por nosotrosH ;na 4orma de conseguir esto es usando S'7"0 como ya vimos en las partes E y [ de esta serie. /a otra 4orma es usar el m%todo au-iliar !E-ecute2uery# de la clase <ata0onte-t y usar una e-presi.n S2/ personali*ada que le demos. 6sando el mtodo ExecuteQue", El m%todo E-ecute2uery toma una e-presi.n S2/ como argumento ) con un con+unto de par(metros) y la e+ecuta contra la base de datos 8incluyendo F"1Ns personali*ados sobre varias tablas. /o que hace que E-ecute2uery sea tan til es que nos permite especi4iar c.mo queremos devolver los valores de la e-presi.n S2/. 'odemos hacer esto pas(ndole un par(metro tipado al m%todo o usando una versi.n gen%rica del m%todo. 'or e+emplo) podemos cambiar el m%todo >et'roducts?y0ategory89 que creamos (ntes =con una e-presi.n /1N2= para que use el m%todo E-ecute2uery para e+ectuar un S2/ que nosotros le digamos&

V?&

0@&

$hora podemos llamar al m%todo >et'roducts?y0ategory89 de la misma 4orma que (ntes&

<e esta manera ser( nuestra consulta S2/ la que se e+ecutar( contra la base de datos 3 y no el S2/ din(mico que generara la e-presi.n /1N2. SQL pe"sonali%ado , t"acGin* de objetos pa"a las actuali%aciones 'or de4ecto cuando obtenemos ob+etos con /1N2 to S2/) se hace un trac ing sobre los cambios que les hacemos. Si llamamos al m%todo !Submit0hanges89# guardar( los datos de 4orma transaccional en la base de datos. Vismo esto en la cuarta parte de esta serie de post.

;na de las caracterstcias del metodo E-ecute2uery89 es que participa en este trac ing de ob+etos para actuali*ar el modelo. 'or e+emplo) podemos escribir el siguiente c.digo para obtener todos los productos de una categora y reba+ar los precios un ADU&

0omo di+imos que el tipo de resultado del E-ecute2uery en el m%todo >et'roducts?y0ategory 4uese !'roduct) /1N2 to S2/ sabe c.mo guardar los cambios. W cuando llamemos a Submit0hanges los guardar(. SQL pe"sonali%ado con clases pe"sonali%adas& El m%todo E-ecute2uery nos permite especi4icar cualquier clase como tipo de resultado de la consulta S2/. /a clase no tiene po"=u haberse creado con el dise:ador /1N2 to S2/) o implementar ninguna inter4a*. 'or e+emplo) de4inimos la clase 'roductSummary con un subcon+unto de las propiedades de 'roduct 84i+(os que hemos usado la caracterstica depropiedades autom(ticas9&

'odramos crear otro m%todo en nuestro <ata0onte-t llamado >et'roductSummaries?y0ategory89 que nos devuelva ob+etos de esa clase. Fi+(os c.mo la siguiente S2/ obtiene s.lo un subcon+unto de 'roduct 3 El m%todo E-ecute2uery89 se encarga de mapea autom(ticamente las propiedades a ob+etos de la clase 'roductSumary&

$hora podemos invocar a este m%todo e iterar sobre los resultados con el siguiente codigo&

SQL pe"sonali%adas pa"a inse"ciones? actuali%aciones , bo""ados& $dem(s de usar S2/ personali*adas para consultar datos) tambi%n podemos hacerlas para insertar) actuali*ar y borrar datos. Esto lo conseguimos creando los m%todos parciales adecuados para cada operacion para la entidad que queramos cambiar en nuestra clase <ata0onte-t. 'odemos usar el m%todo E-ecute0ommand del <ata0onte-t para escribir el S2/ que queramos. 'or e+emplo) para sobreescribir el comportamiento de borrado de la clase 'roduct de4inimos el siguiente m%todo parcial&

W si escribimos un c.digo que elimine un producto de la base de datos) /1N2 to S2/ llamar( al m%todo <elete'roduct 3 que e+ecutar( una S2/ personali*ada en lugar del S2/ din(mico que /1N2 to S2/ usara&

2esumen El "7, /1N2 to S2/ genera y e+ectua un S2/ din(mico para las consultas) actuali*aciones) inserciones y borrados contra la base de datos. 'ara escenarios m(s avan*ados) o en caso donde queramos un control total sobre el S2/ que se e+ecuta) tambi%n podemos personali*ar el "7, para que e+ecute S'7"0s) o nuestras consultas S2/ personali*adas. Esto nos da una gran 4le-ibilidad a la hora de construir y e-tender nuestra capa de datos.

LINQ to SQL (Parte . Uso de e/*resiones LINQ *ersonali#adas con el control )


'ublicado en .NET) $S' .NET) /1N2) /1N2 to S2/) Scott >uthriP) S2/ a AB&JE pm por Fuanma

En las ltimas semanas he escrito una serie de post sobre /1N2 to S2/. /1N2 to S2/ es un "7, que viene con .NET I.J) y nos permite modelar bases de datos relacionales en clases. 'odemos usar e-presiones /1N2 para consultar la base de datos y tambi%n para actuali*ar) insertar y borrar datos. $qu ten%is los enlaces a los di4erentes post de la serie& 'arte A& 1ntroducci.n a /1N2 to S2/ 'arte B& <e4iniendo el modelo de datos. 'arte I& 0onsultando la base de datos 'arte Q& $ctuali*ando la base de datos. 'arte J& Enla*ar controles de inter4a* de usuario con el $S'&/inq<atSource 'arte E& "btener datos con procedimientos almacenados. 'arte [& $ctuali*ando la base de datos con procedimientos almacenados. 'arte S& E+ecutar consultas S2/ personali*adas.

En la quinta parte vimos el control Masp&/inq<ataSourceN de .NET I.J y hablamos sbre c.mo podemos enla*ar controles de $S'.NET a /1N2 to S2/. Tambi%n vimos c.mo usarlo con el control Masp&/istViewN 8El control asp&/istView 8'arte A 3 0reaci.n de una p(gina de listado de productos con una 0SS limpia99 En ambos artculos las consultas que hacamos eran relativamente sencillas 8la clausula where se e+ecutaba sobre una tabla simple9. En el post de hoy veremos c.mo usar toda la potecia de las consultas de /1N2 con el control /inq<ataSource) y veremos c.mo usar cualquier e-presion /1N2 to S2/ con %l. !e=ue(a "ecapitulaci5n: @asp:Lin=DataSou"ceA con una sentencia <8e"e& En estos dos post vimos c.mo usar el 4iltro del control /inq<atasource para declarar un 4iltro en un modelo /1N2 to S2/.

'or e+emplo) supongamos que hemos creado un modelo /1N2 to S2/ de la base de datos Northwind 8que ya vimos en la segunda parte de esta serie9) podramos declarar un control Masp&/inq<ataSourceN en la p(gina con un 4iltro MwhereN que devuelve aquellos productos de una categora dada. 8especi4icada a partir del valor !categoryid#9.

/uego) podemos enla*ar un Masp&gridViewN a este datasource y habilitar la paginaci.n) edici.n y ordenaci.n.&

0uando e+ecutamos la p(gina anterior tendremos un >ridView que soportar( autom(ticamente la ordenaci.n) paginaci.n y edici.n sobre el modelo de 'rodut&

;sando los par(metros del MwhereN de esta 4orma 4unciona muy bien en escenarios tpicos. 'ero Gqu% pasa si que el 4iltrado de 'roduct sea m(s comple+oH 'or e+emplo) GSi s.lo queremos mostrar los productos suministrados por un con+unto din(mico de paisesH 6so del e)ento Selectin* del @asp:Lin=DataSou"ceA En consultas personali*adas podemos implementar un mane+ador de eventos para el evento !Selecting# en el control Masp&/inq<ataSourceN. 0on este mane+ador podemos escribir el c.digo que queramos para obtener los datos. Esto lo podemos hacer con una e-presi.n /1N2 to S2/) o llamar a unprocedimiento almacenado o usar una e-presi.n S2/ personali*ada. ;na ve* que obtenemos la secuencia de datos) todo lo que tenemos que hacer es asignar la propiedad !7esult# al ob+eto /inq<ataSourceSelectEvent$rgs. El Masp&/inq<ataSourceN usar( esta secuencia como los datos con los que traba+ar(. 'or e+emplo) aqu ten%is una consulta /1N2 to S2/ que obtiene aquellos productos de los proveedores de un con+unto de pases& V?&

0@&

Nota: No tenemos que escribir la consulta en el c,digo del mane-ador. 1na soluci,n m0s limpia ser4a encapsularla en un m5todo de ayuda al que podr4amos llamar desde el propio mane-ador. Esto lo +imos en laparte 6 de esta serie 7usando el m5todo 8et'roducts$y%ategory9.
$hora) cuando e+ecutemos la p(gina usando este mane+ador) s.lo obtendremos los productos de los proveedores de ciertos pases&

;na de las cosas m(s interesantes es que la paginaci.n y la ordenaci.n siguen 4uncionando en nuestro >ridView 3 aunque estemos usando el evento Selecting. Esta l.gica de paginaci.n y ordenaci.n ocurre en la base de datos 3 es decir) s.lo devolvemos los AD productos de la base de datos que necesitamos para el ndice actual del >ridView 8supere4iciente9. "s estar%is preguntando 3 Gc.mo es posible que tengamos una paginaci.n y ordenaci.n e4iciente incluso cuando lo hacemos con un evento personali*adoH. /a ra*.n es que /1N2 usa el modelo de e+ecuci.n en di4erido 3 es decir) la consulta no se e+ecuta hasta que intentamos iterar sobre los resultados. ;no de los bene4icios de este modelo es que nos permite componer consultas con otras consultas) y a:adirles !comportamiento#. 'od%is leer m(s sobre esto en la tercera parte de la serie /1N2 to S2/. En nuestro evento !Selecting# estamos declarando una consulta /1N2 personali*ada que queremos e+ecutar y luego se la asignamos a la propiedad !e.7esult#. 'ero an no la hemos e+ecutado 8ya que no hemos iterado sobre los resultados o llamado a los m%todos To$rray89 o To/ist899. El /1N2<ataSource es capa* de a:adir autom(ticamente los operadores S ip89 y Ta e89 al aconsulta) as como aplicarle una e-presi.n !orderby# _ siendo todos estos valores calculados autom(ticamente a partir del ndice de p(gina y las pre4erencias de ordenaci.n del >ridView. S.lo entonces el

/1N2<ataSource e+ecuta la e-presi.n /1N2 y obtiene los datos. /1N2 to S2/ se encarga de que la l.gica de ordenaci.n y paginado se haga en la base de datos 3 y que s.lo se devuelvan AD 4ilas de productos. Fi+(os c.mo podemos seguir usando el >ridView para editar y borrar datos) incluso cuando usamos el evento !Selecting# del /1N2<ataSource&

El soporte de edicion5borrado 4uncionar( mientras que el evento Selecting asigne la secuencia de resultados a la propiedad 7esult y sean ob+etos entidad 8por e+emplo& una secuencia de 'roduct) Supplier) 0ategory) "rder) etc9. El /inq<ataSource administrar( los casos en el que los controles hagan actuali*aciones sobre ellos. 'ara leer mas sobre c.mo 4uncionan las actuali*aciones con /1N2 to S2/) leed laparte cuatro de esta serie) y luego la parte quinta para ver las ;pdates en accci.n. 2eali%ano p"o,ecciones de consultas pe"sonali%adas con el e)ento Selectin*& ;na de las caractersticas m(s poderosas de /1N2 es la habilidad de !4ormar# o !proyectar# datos. 'odemos hacer esto en una e-presi.n /1N2 to S2/ para indicar que queremos obtener s.lo un subcon+unto de valores de una entidad) y5o

calcular nuevos valores din(micamente al vuelo con e-presiones personali*adas que de4inamos. 'ara leer m(s sobre esto leed la tercera parte de la serie. 'or e+emplo) podemos modi4icar el evento !Selecting# para calcular un >ridView para que muestre un subcon+unto de in4ormaci.n de 'roduct. En el grid queremo mostrar el 'roduct1<) 'roductName) 'roduct ;nit'rice) el nmero de pedidos de ese producto) y el total de pedidos de ese producto. 'odemos calcular estos dos ltimos campos con la siguiente e-presi.n /1N2& V?&

0@&

Nota: El m5todo Sum para calcular el .e+enue es un e-emplo de unm5todo de e/tensi,n. La !unci,n es una e/presi,n lambda. El tipo de resultados creados de la consulta LINQ es un tipo an,nimo : ya que el tipo es in!erido de la consulta. ;5todos de e/tensi,n, e/presiones Lambda, y los tipos an,nimos son nue+as caracter4sticas de <$ y %= en <S >??6.
El resultado de esta e-presi.n /1N2 cuando lo enla*amos al >ridView es el siguiente&

Fi+aos que la paginaci.n y la ordenaci.n sigue 4uncionando en el >ridView 3 aunque estemos usando una proyecci.n de /1N2 para los datos. ;na caracterstica que no Bunciona"> con las proyecciones es el soporte para la edici.n. Esto es debido a que estamos haciendo una proyecci.n personali*ada en el m%todo Selecting) y el /1N2<ataSource no tiene 4orma de saber c.mo actuali*ar la entidad. Si queremos a:adir soporte para la edici.n en este caso) tendremos que crear un control "b+ect<ataSource 8al que le pondremos un m%todo ;pdate personali*ado para contorlarlos9) o hacer que el usuario navegue a una nueva p(gina para hacer la actuali*aci.n 3 y mostrar un <etailsView o FormView enla*ado a la entidad 'roducto para la edici.n 8y no intentar hacerlo en el grid9. 2esumen 'odemos reali*ar consultas personali*adas sobre el modelo /1N2 to S2/ usando el soporte integrado de 4iltrado del /1N2<ataSource. 'ara habilitar opiciones de 4iltrado m(s avan*adas) usaremos el m%todo Selecting del /1N2<ataSource. Esto no permitir( crear la l.gica que queramos para obtener y 4iltrar datos /1N2 to S2/. 'odemos llamar a m%todos para obtener los datos) usar E-presiones /1N2) llamar a procedimientos almacenados o invocar una e-presi.n S2/ personali*ada para hacer esto.

You might also like