Vous êtes sur la page 1sur 114

Usando LINQ to SQL (1 Parte)

En los ltimos meses he escrito una serie de post que cubran algunas de
las caracterstcias que van a venir con Visual Studio y .NET Framework
"Orcas". Aqu tenis los enlaces:
Propiedades automticas, inicializadores de objectos e inicializadores
de colleciones.
Mtodos de extensin.
Expresiones Lambda.
Sintaxis de consultas.
Tipos Annimos
Las caractersticas anteriores hacen que la consulta de datos sea un
concepto de primera clase. Conocemos a este modelo de programacin
como "LINQ" - que viene de .NET Language Integrated Query.
Los desarrolladores pueden usar LINQ con cualquier fuente de datos.
Pueden expresar consultas eficientemente en los lenguajes de
programacin que eligan, opcionalmente transformar/incrustar los resultados
de las consultas en el formato que quieran, y entonces manipular fcilmente
los resultados. Los lenguajes habilitados para LINQ pueden aportar
seguridad de tipos y chequeo en tiempo de compilacin el las expresiones
de consulta, y desarrollar herramientas que aporten intelisense, debugging,
y un gran soporte para refactoring cuando escriban cdigo de LINQ.
LINQ soporta un modelo de extensibilidad muy rico que facilita
la creacin de operadores eficientes para fuentes de datos. La versin
"Orcas" del .NET Framework viene con libreras que habilitan LINQ
sobre objetos, XML y bases de datos.

Qu es LINQ to SQL?
LINQ to SQL es una implementacin de O/RM(object relational mapping,
mapeador de objetos relacionales) que viene con la versin "Orcas" del
.NET Framework, y nos permite modelar bases de datos relacionales con
clases de .NET. Podemos consultar bases de datos con LINQ, as como
actualizar/aadir/borrar datos de ellas.
Modelando bases de datos con LINQ to SQL:
Visual Studio "Orcas" viene con un diseador de LINQ to SQL que nos
aporta una forma fcil de modelar y visualizar una base de datos como un
modelo de objeto de LINQ to SQL. El prximo post cubrir en ms
profundidad cmo usar este diseador (podis ver este videoque hice en
Enero para verme construir un modelo LINQ to SQL).
Usando ese diseador LINQ to SQL puedo crear fcilmente una
representacin de la base de datos "Northwind":

El diseo de arriba define cuatro clases: Product, Category, Order y


OrderDetail. Las propiedades de cada clase mapean las columnas de cada
table en la base de datos. Cada instancia de esa clase representa una fila
en las tablas.
Las flechas entre las cuatro clases de arriba representan las
asociaciones/relaciones entre las diferentes entidades. Son tpicamente
modeladas como relaciones primary-key/foreign-key en la base de datos. La
direccin de las flechas en el diseador indican si la relacin es uno-a-uno o
uno-a-varios. Se aadiran propiedades fuertemente tipadas a las entidades
basndose en esto. Por ejemplo, la clase Category de arriba tiene una
relacin de uno-a-varios con la clase Product. Esto implica que tendr una

propiedad "Categories" que es una coleccin de objetos Product con esa


categora. La clase Product entonces tiene una propiedad "Category" que
apunta a una instancia de la clase Category representando la categora a la
que pertenece el producto.
El panel de la derecha del diseador LINQ to SQL contiene una lista de
procedimientos almacenados que interactan con nuestro modelo de base
de datos. En el ejemplo de arriba hemos aadido un SPROC (Procedimiento
almacenado) "GetProductsByCategory". Como entrada recibe un
categoryID, y devuelve una secuencia de Product como resultado. Veremos
cmo llamar a este procedimiento almacenado en un ejemplo.
Entendiendo la clase DataContext
Cuando pulsis el boton "save" del diseador de LINQ to SQL, Visual Studio
generar clases .NET para representar las entidades y las relaciones de la
base de datos que hemos modelado. Por cada archivo aadido a nuestra
solucin por el diseador LINQ to SQL tambin se generar una clase
DataContext. Esta clase es a traves de la cual realizaremos las consultas a
las entidades de nuestra base de datos. Esta clase tendr propiedades que
representarn a cada tabla que hemos modelado, as como mtodos para
cada procedimiento almacenado que aadamos.
Por ejemplo, aqu tenis la clase NorthwindDataContext:

Ejemplos de LINQ to SQL


Una vez que hemos modelado nuestra base de datos con el diseador de
LINQ to SQL, podemos escribir cdigo fcilmente para trabajar con l. Aqu
tenis unos cuantos ejemplos que muestran tareas comunes con datos:
1) Consultando Products de la base de datos
El siguiente cdigo usa una consulta LINQ para obtener una secuencia
IEnumerable de objetos Product. Fijos que este cdigo est consultando a
traves de la relacin Product/Category para obtener aquellos productos de la
categora "Beverages".
C#:

VB:

2) Actualizando un producto en la base de datos.


El cdigo siguiente muestra cmo obtener un producto de la base de datos,
actualizar su precio, y guardar los cambios en la base de datos:
C#:

VB:

Nota: VB en "Orcas" Beta1 no soporta Lambdas an. Pero en la Beta2 s


-de forma que el cdigo anterior se podr escribir de una forma ms
concisa.

3) Aadir una nueva categora y dos nuevos productos en la base de


datos.
El siguiente cdigo muestra cmo crear una nueva categora, y entonces
crear dos nuevos productos y asociarlos a la nueva categora. Los tres son
despus guardados en la base de datos.
Fijaos como no necesitamos administrar manualmente las relaciones
primarykey/foreignkey. Slo tenemos que aadir los objetos Product en la
coleccin "Products" de la categora, y luego aadir el nuevo objeto
Category en la coleccin de "Categories" del DataContext, LINQ to SQL
sabr automticamente crear las PF/FK necesarias:
C#:

4)Borar productos de la base de datos.


El cdigo siguiente muestra cmo borrar todos los productos Toy de la base
de datos:
C#:

VB:

5) Llamar a un procedimiento almacenado.


El cdigo siguiente muestra cmo obtener entidades de la tabla Product sin
usar una consulta LINQ, sino llamando al procedimiento almacenado
"GetProductsByCategory" que aadimos a nuestro modelo de datos. Fijos
que cuando obtenemos los resultados de la tabla Product, podemos
actualizar/borrarlos y llamar a db.SubmitChanges() para hacer las
modificaciones en la base de datos.
C#:

VB:

6) Obtener productos con paginado del lado del servidor


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

C#:

VB:

Resumen:
LINQ to SQL nos permite modelar la capa de datos de nuestras aplicaciones
de una forma simple y limpia. Una vez que hayamos definido nuestro
modelo de datos, podemos realizar consultas, inserciones, actualizaciones y
borrados sobre ella de forma fcil y eficiente.
Espero que esta introduccin os haya abierto el apetito de aprender ms. En
las prximas semanas continuar esta serie de post explorando el LINQ to
SQL en ms detalle.
Espero que sirva.
Scott.
Traducido por: Juan Mara La Ramos. Microsoft Student Partner

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

En la primera parte de la serie de post sobre LINQ to SQL habl sobre


"qu es LINQ to SQL?" y vimos por encima algunos escenarios que
permite.
En aqul post pusimos unos cuantos ejemplos de cdigo donde
demostrbamos cmo mejorar la parte de datos usando LINQ to SQL:
Cmo consultar una base de datos.
Cmo actualizar filas en una base de datos
Cmo aadir y relacionar varias filas en una base de datos.
Cmo eliminar filas de la base de datos.
Cmo llamar a procedimientos almacenados.
Cmo obtener datos con paginacin en el servidor.
Mejoramos todos estos escenarios usando un modelo de clases de LINQ to
SQL como ste:

En este segundo post de la serie vamos a ver en ms detalle cmo crear el


modelo anterior con LINQ to SQL.
LINQ to SQL, el diseador de LINQ to SQL, y todas las caractersticas que
estamos viendo saldrn con la versin de .NET 3.5 y en la release de Visual
Studio "Orcas".
Podis seguir todos los pasos siguientes descargndo tanto Visual Studio
"Orcas" Beta 1o Visual Web Developer Express "Orcas" Beta 1. Podis
instalar las dos y usarlas sin ningn problema con Visual Studio 2005.
Crear un nuevo modelo de datos LINQ to SQL

Podemos aadir un modelo de datos de LINQ to SQL a un projecto


ASP.NET, Class Library o Windows, con la nueva opcin "Add New Item"
seleccionando "LINQ to SQL":

Seleccionando "LINQ to SQL" lanzar el diseador de LINQ to SQL, y nos


permitir modelar las clases que representen una base de datos relacional.
Tambin crear una clas fuertemente tipada "DataContext" que tendr las
propiedades que representarn cualquier tabla que modelemos de la base
de datos, as como mtodos para cada procedimiento almacenado que
modelemos. Como describimos en la primera parte de esta serie de post, la
clase DataContext es el conducto principal que usaremos tanto para
consultar la base de datos como para guardar los cambios que hagamos.
Aqu tenis una captura de pantalla de un diseo LINQ to SQL ORM vaco,
es lo que veris despues de crear un nuevo modelo de datos LINQ to SQL:

Clases Entidad (Entity)


LINQ to SQL nos permite modelar clases que mapeen una base de datos.
Estas clases son tpicamente conocidas como "Clases Entidad" (en ingles
"Entity Classes") y a las instancias se las conoce como "Entidades" (en
ingles "Entities"). Las clases entidad mapean a tablas de una base de datos.
Las propiedades de una clase entidad normalmente mapean las columnas
de la tabla. Cada instancia de una clase entidad representa a una fila de una
tabla de la base de datos.
Las clases entidad definidas por LINQ to SQL no tienen que derivar de una
clase base especfica, lo que significa que pueden heredar de cualquier
objeto que queramos. Todas las clases creadas por el diseador de LINQ to
SQL se definen como "clases parciales" - con lo que podemos,
opcionalmente, aadir propiedades adicionales, mtodos y eventos.
A diferencia de la caracterstica de DataSet/TableAdapter que aporta VS
2005, cuando usamos el diseador de LINQ to SQL no tenemos que

especificar qu consultas SQL se tiene que usar cuando creamos el modelo


de datos y la capa de acceso.
En lugar de eso, nos centramos en definir las clases entidad, cmo se
mapean con la base de datos, y las relaciones entre ellas. La
implementacin del ORM de LINQ to SQL se encargar de generar la lgica
de ejecucin SQL por nosotros en tiempo de ejecucin para que podamos
interactuar y usar las entitades de datos. Podemos usar sintaxis de
consultas LINQ para indicar cmo consultar nuestro modelo de datos de
forma fuertemente tipada.
Crear clases entidad de la base de datos.
Si ya tenemos un esquema de base de datos definido, podemos usarlo para
crear clases entidad LINQ to SQL.
La forma ms sencilla de conseguirlo es abrir la base de datos desde el
"Server Explorer" de Visual Studio, seleccionar las tablas y vistas (Views)
que queramos modelar, y arrastrarlas al diseador LINQ to SQL:

Cuando aadimos estas dos tablas (Categories y Products) y una vista


(Invoices) de la base de datos "Northwind" al diseador de LINQ to SQL,
tendremos las siguientes clases entidad creadas a partir del esquema de la
base de datos:

Usando estas clases, podemos ejecutar todos los ejemplos de cdigo


(excepto el de procedimientos almacenados) que vimos en la primera
parte de esta serie sobre LINQ to SQL. No tenemos que aadir ningn
cdigo adicional o configuracin para habilitar los escenarios de consulta,
insercin, actualizacin, borrado, y paginacin en el servidor.
Nombrado y pluralizacin
Una de las cosas de las que os daris cuenta usanto el diseador de LINQ
to SQL es que automticamente "pluraliza" los nombres de las tablas y
columnas cuando crea las clases entidad basdas en el esquema de la
base de datos. Por ejemplo: la tabla "Products" del ejemplo se resuelve en
una clase "Product", y la tabla "Categories" se resuelve en la clase
"Category". Este nombrado de clases hace que vuestro modelo sea ms
consistente con las convenciones de nomenclatura de .NET, y encuentro
bastante til que el diseador haga esto por mi (especialmente cuando
aadimos muchas tablas a nuestro modelo).

Si no os gusta el nombre de una clase o propiedad que el diseador ha


generado, siempre podris cambiarlo por el que queris. Podis hacerlo
editanto el nombre de la entidad/propiedad en el mismo diseador o
cambiarlo en la rejilla de propiedades:

Esta habilidad de nombrado de entidades/propiedades/asociaciones es muy


til en un gran nmero de casos. En particular:
1) Cuando cambie el nombre de una tabla/columna de vuestra base de
datos. Como vuestras entidades tendrn nombres diferentes, podis decidir
actualizar las reglas de mapeado y no el cdigo de vuestra aplicacin o las
consultas para usar esas nuevas tablas/columnas.
2) Cuando en el esquema de la base de datos tengais nombres que no son
"limpios". Por ejemplo, en lugar de usar "au_lname" y "au_fname" para los
nombres de las propiedades en una clase entidad, podis usar los nombres
de "LastName" y "FirstName" en vuestras clases entidad y programar con
esos nombres, en vez de cambiarlo en la base de datos.
Relaciones
Cuando arrastremos objetos del "server explorer" al diseador "LINQ to
SQL", Visual Studio comprobar las relaciones de clave primaria y ajenas de
los objetos, y basndose en ellas crear relaciones por defecto entre las
diferentes clases entidad que genere. Por ejemplo, cuando aadimos las
tablas Products y Categories de la base de datos NorthWind al diseador
LINQ to SQL podemos ver que se ha deducido una relacin de uno a n
entre ellas (esto se indica con la felcha del navegador):

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

Si no nos gusta cmo el diseador a nombrado a la relacin, siempre


podrmos cambiarlo. Slo hay que hacer clic en la felcha en el diseador,
ver las propiedades y cambiar el nombre.
Retrasar la carga

LINQ to SQL permite a los desarrolladores especificar si las propiedades de


las entidades deben precargarse o retrasarse hasta el primer acceso.
Podemos personalizar las reglas de precarga/retraso para las propiedades
de las entidades seleccionando cualquier propiedad o asociacin en el
diseador, y en las propiedades poner la propiedad "Delay Loaded" a true o
false.
Por poner un ejemplo, imaginemos la clase entidad "Category" del modelo
anterior. La tabla "Categories" de la base de datos "NorthWind" tiene una
columna "Picture" que contiene una imagen (potencialmente grande) para
cada categora, y slo queremos esa imagen cuando vaya a usarla (y no
cuando est haciendo una consulta para obtener los nombres de las
categoras en una lista).
Podramos configurar la propiedad Picture para que se retrase su carga
seleccionandola en el diseador de LINQ to SQL y en las propiedades poner
"Delay Loaded" a true:

Nota: Adems de configurar el significado de la precarga/retraso de las


entidades, podemos sobreescribirlo va cdigo cuando hagamos consultas
LINQ en las clases entidad (lo veremos en el siguiente post de esta serie).
Usando procedimientos almacenados.
LINQ to SQL nos permite modelar procedimientos almacenados como
mtodos de nuestra clase DataContext. Por ejemplo, supongamos que
hemos definido un procedimiento almacenado simple para obtener la
informacin de un producto de un categoryID:

Podemos usar el server explorer de Visual Studio y arrastrar este


procedimiento almacenado al diseador de LINQ to SQL para obtener un
mtodo fuertemente tipado que invocar a este procedimiento almacenado.
Si lo arrastramos encima de la entidad "Product" en el diseador, el
diseador declarar que el procedimiento almacenado devuelve un
IEnumerable<Product>:

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

Usar procedimientos almacenados para actualizar/borrar/insertar


datos.
Por defecto LINQ to SQL crear automticamente expresiones SQL
apropiadas para cuando tengamos que insertar/actualizar/borrar entidades.
Por ejemplo, si escribimos el siguiente cdigo LINQ to SQL para actualizar
algunos valores en una instancia de la entidad "Product":

LINQ to SQL crear y ejecutar una sentencia "UPDATE" apropiada para


cuando aceptemos los cambios (Veremos esto en ms profundidad en otros
post).
Podemos definir procedimientos almacenados personalizados para INSERT,
UPDATE, DELETE. Para configurar esto, hacemos clic en una entidad del
diseador LINQ to SQL y en las propiedades de Delete/Insert/Update, en el
botn "...", y ponemos un procedimiento almacenado que ya hayamos
definido.

Lo curioso es que el cambio de estas propiedades se est realizando en la


capa de mapeo de LINQ to SQL - lo que implica que la actualizacin del
cdigo que vimos ntes sigue funcionando sin tener que hacer ninguna
modificacin. Con esto libramos a los desarrolladores de que si
cambiamos el modelo de datos LINQ to SQL, no tienen que tocar ningn
cdigo para que sigua funcionando si deciden poner un procedimiento
almacenado personalizado.
Resumen

LINQ to SQL provee una forma limpia de modelar las capas de datos de
nuestras aplicaciones. Una vez que tengamos nuestro modelado de datos,
podemos realizar de forma eficiente consultas, inserciones, actualizaciones,
y borrados sobre l.
Con el diseador de LINQ to SQL que viene en Visual Studio y en Visual
Web Developer Express podemos crear y administrar nuestros modelso de
datos para LINQ to SQL extremadamente rpido. El diseador LINQ to SQL
tambin permite una gran flexibilidad que nos permite personalizar el
comportamiento por defecto y sobreescribir/extender el sistema para que se
adapte a nuestras necesidades.
En prximos post usaremos este modelo que hemos creado para ver en
ms detalle los procesos de consulta, inserciones, actualizaciones y
borrados. En estos post tambin veremos cmo aadir validaciones
negocio/datos personalizadas a las entidades que hemos diseado.
Mike Taulty tiene una gran cantidad de videos sobre LINQ to SQL aqu, os
recomiendo que los veis. As tenis una forma de aprender viendo cmo se
usa LINQ to SQL.
Espero que sirva.
Scott.
Traducido por: Juan Mara La Ramos. Microsoft Student Partner

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

El mes pasado empez una serie de post sobre LINQ to SQL. LINQ to
SQL es un framework O/RM (Object relational mapping) que viene como
parte del .NET Framework 3.5, que nos permite modelar de forma sencilla
bases de datos relacionales con clases de .NET. Podemos usar, por tanto,
expresiones LINQ tanto para consultar a la base de datos como para
actualizar/inertar/borrar datos.
Aqu tenis los enlaces a los primero dos post de esta serie:
Usando LINQ to SQL (1 Parte)
LINQ to SQL (2 Parte - Definiendo nuestras clases del modelo
de datos)
En el post de hoy vamos a ver en ms detalle cmo usar el modelo de
datos que creamos en la segunda parte, y veremos cmo usarlo para
consultar datos en un proyecto ASP.NET.
Modelo de la base de datos Northwind con LINQ to SQL
En el segundo post de la serie vimos cmo crear un modelo de clases
LINQ to SQL usando el diseador de LINQ to SQL que viene con VS 2008.
Aqu tenis el modelo que creamos a partir de la base de datos de
ejemplo Northwind:

Obteniendo productos.
Una vez que tenemos definido nuestras clases del modelo de datos,
podemos consultar y obtener fcilmente datos de nuestra base de datos.
LINQ to SQL nos permite esto usando la sintxis de consultas de LINQ
sobre la clase NorthwindDataContext que creamos con el diseador LINQ
to SQL.
Por ejemplo, para obtener e iterar sobre una secuencia de objetos Product
podemos escribir el siguiente cdigo:

En esta consulta hemos usado la sentencia "where" en nuestra consulta


LINQ para devolver aquellos productos de una categora. Estamos usando
el campo/propiedad CategoryID del producto para hacer el filtro.
Una de las cosas que nos aporta LINQ to SQL es que nos da una total
flexibilidad en cmo consultar nuestros datos, y podemos aprovecharnos
de las asociaciones que hicimos cuando modelamos las clases de LINQ to
SQL para hacer consultas ms naturales y ricas sobre la base de datos.
Por ejemplo, podemos modificar el filtro de la consulta por el CategoryName
en lugar de por el CategoryID con la siguiente consulta LINQ:

Fijos en cmo estamos usando la propiedad "Category" de cada objeto


Product para filtrarlos por CategoryName. Esta propiedad fue creada
automticamente por LINQ to SQL ya que modelamos las clases Category
y Product con una relacin "varios a uno" en la base de datos.

Por poner otro ejemplo del uso de las relaciones de nuestro modelo, podramos escribir la siguiente consulta LINQ para obtener aquellos productos
que tengan ms de cinco rdenes para ellos:

Fijos cmo usamos la coleccin "OrderDetails" que LINQ to SQL cre


en cada clase Product (debido a la relacin 1 a varios que modelamos en
el diseador LINQ to SQL).
Visualizando consultas LINQ to SQL en el debugger
Los ORM como LINQ to SQL administran automticamente la creacin y
la ejecucin del cdigo SQL cuando realizamos consultas o
actualizaciones sobre su modelo de objetos.
Una de los mayores preocupaciones que tienen los desarrolladores sobre
los ORMs es "pero qu cdigo SQL se est ejecutando?" Una de las
cosas que hace LINQ to SQL es poder ver exctamente qu cdigo SQL
se est ejecutando cuando ejecutamos nuestra aplicacin con el
debugger.
Con la beta 2 de VS 2008 podemos usar el nuevo plug-in de visualizacin
LINQ to SQL para ver (y testear) cualquier consulta LINQ to SQL.
Simplemente aadimos un breakpoint y pasamos el ratn por encima y
hacemos clic en la lupa para visualizar esa consulta:

ESto nos mostrar un cuadro de dilogo que nos dir exactamente la


SQL que LINQ to SQL usar cuando se ejecute la consulta para obtener
los objetos Product:

Si pulsamos el botn "Execute" de este dilogo nos permitir evaluar el


SQL dentro del debugger y nos mostrar los resultados de la base de
datos:

Obviamente esto hace realmente fcil ver qu lgica de consultas SQL


est realizando LINQ to SQL. Fijos que podemos sobreescribir la SQL
que LINQ to SQL ejecutar si queremos cambiarlo - sin embargo, en el
98% de los casos creo que os dareis cuenta de que el cdigo SQL que
LINQ to SQL ejecuta es realmente bueno.
Enlazando consultas LINQ to SQL a controles ASP.NET
Los resultados de las consultas LINQ implementa la interfaz IEnumerable la cual es una interfaz que los controles de servidor de ASP.NET soportan
para enlazar datos. Lo que implica que podemos enlazar los resultados de
cualquier consulta LINQ, LINQ to SQL, o LINQ to XML a cualquier control
ASP.NET.
Por ejemplo, podemos declarar un control <asp:gridview> en una pgina
.aspx de la siguiente forma:

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


escribimos antes:

Esto generar una pgina como la siguiente:

Restringiendo los resultados de la consulta.


Hasta ahora, cuando evaluamos una consulta de productos, estamos
obteniendo por defecto todas las columnas de datos necesarias para cubrir
la entidad de Product.
Por ejemplo, esta consulta para obtener productos:

El resultado de esta consulta es:

Normalmente slo queremos un subconjunto de los datos de cada


producto. Podemos usar la nueva caracterstica que LINQ y los
compiladores de C# y VB tienen para indicar que slo queremos un
subconjunto de los datos, modificando la consulta LINQ to SQL de la
siguiente forma:

Con esto obtendremos un subconjunto de los datos que se obtienen de la


base de datos (como vemos con el visor del debugger):

Lo realmente til de LINQ to SQL es que podemos aprovecharnos de las


asociaciones entre clases de nuestro modelo de datos cuando restringimos
los datos. Esto nos permite expresar consultas tiles y muy eficientes. Por
ejemplo, la siguiente consulta obtiene los ID y los nombres de la entidad
Product, el nmero total de pedidos que hemos hecho de productos, y los
suma al total de pedidos de Productos:

La expresin a la derecha de la propiedad "Revenue" es un ejemplo del


uso del mtodo de extensin "Sum" de LINQ. Toma una expresin
Lambda que devuelve el valor de cada pedido de producto como argumento.
LINQ to SQL es listo y es capaz de transformar la expresin LINQ anterior
al siguiente SQL cuando es evaluado (con el visor del debugger):

La sentencia SQL anterior hace que los valores NumOrders y Revenue


se calculen dentro del servidor SQL, y devuelve los siguientes valores de la
base de datos (realmente rpido):

Podemos enlazar el resultado anterior a nuestro gridview:

BTW - en caso de que os lo preguntis, tenemos intellisense en VS 2008


cuando escribimos estos tipos de restricciones en las consultas LINQ:

En este ejemplo estamos declarando un tipo annimo que usa


la inicializacin de objetospara amoldar y definir la estructura del resultado.
Y seguimos teniendo intellisense en VS 2008, chequeo de compilacin y
soporte para refactoring con estos tipos anonimos:

Paginando los resultados de la consulta.


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

Fijos que no aadimos ni Skipt() ni Take() en la primera consulta - sino


que lo hacemos despus de la consulta (cuando lo enlazamos a la fuente
de datos del GridView). Muchos me preguntan "pero esto no significa que
primero obtiene todos los datos de la base de datos y luego hace la
paginacin (esto es malo)?" No. La cuestin es que LINQ usa un modelo
de ejecucin en diferido, es decir, la consulta no se ejecuta hasta que se
itera sobre los resultados.
Uno de los beneficios de este modelo de ejecucin en diferido es que nos
permite crear consultas en varias lneas de cdigo (lo que mejora la
claridad). Tambin nos permite crear las consultas despus de otras - lo
que nos permite composiciones ms flexibles y reutilizacin.

Una vez que tenemos el mtodo BindProduct(), podemos escribir el


siguiente cdigo en nuestra pgina para obtener el ndice de inicio de la
consulta y hacer que los productos sean paginados y mostrados en el
gridview:

Esto nos dar una pgina de productos, filtrada para mostrar aquellos
productos que tengan ms de cinco pedidos, mostrando datos calculados
dinmicamente, y que son paginables a partir de una cadena de consulta:

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

Esto hace realmente fcil y eficiente navegar por grandes cantidades de


datos.
Resumen
Hemos visto por encima alguna de las cosas que LINQ to SQL nos ofrece.
Para aprender ms sobre expresiones LINQ y las nuevas caractersticas
de consultas que traen los compiladores de C# y VB con VS 2008, leed
estos post:
Nuevas caractersticas de la nueva versin de C# Orcas
Mtodos de extensin.
Expresiones Lambda
Sintaxis de consultas
Tipos annimos

En el prximo post de esta serie sobre LINQ to SQL veremos cmo


podemos aadir lgica de validacin a nuestro modelo de clases de
datos, y mostraremos cmo podemos usarlo para encapsular la lgica de
negocio que se ejecutar con cada actualizacin, insercin o borrado de
nuestros datos. Veremos casos ms avanzados, cmo usar el nuevo
control <asp:LINQDataSource> para aadir enlaces de datos declarativos
a controles ASP.NET, resolucin de errores de concurrencia optimista, y
ms.
Espero que sirva.
Scott.
Traducido por: Juan Mara La Ramos. Microsoft Student Partner.

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

n las ltimas semanas he escrito una serie de post sobre LINQ to SQL.
LINQ to SQL es un O/RM(object relational mapper) integrado en la versin
3.5 del framework de .NET, y nos permite modelar fcilmente bases de
datos relacionales en clases de .NET. Podemos usar expresiones LINQ
tanto para consultar la base de datos como para actualizar, insertar y borrar
datos.
Aqu tenis los links a los tres primeros post:
Parte 1: Introduccin a LINQ to SQL
Parte 2: Definiendo el modelo de datos.
Parte 3: Consultando la base de datos
En el post de hoy veremos cmo usar el modelo de datos que hemos
creado, y usarlo para actualizar, insertar y borrar datos. Tambin veremos
cmo integrar reglas de negocio y crear lgica de validacin personalizada
con nuetro modelo de datos.
Modelado de la base de datos NorthWind con LINQ to SQL
En la segundo post de esta serie, vimos cmo crear el modelo de clases con
el diseador de LINQ to SQL que trae VS 2008. Aqu tenis el modelo que
creamos a partir de la base de datos de ejemplo Northwind que usaremos
en este post:

Cuando definimos el modelo definimos cinco clases: Product, Category,


Customer, Order y OrderDetail. Las propiedades de cada clase mapean las
diferentes columnas de las tablas correspondientes en la base de datos.
Cada instancia de cada clase es una entidad que representa una fila de
cada tabal.
Cuando definimos nuestro modelo de datos, el diseador LINQ to SQL cre
una clase llamada DataContext que proporciona todo lo necesario para

poder consultar/actualizar la base de datos. En nuestro ejemplo, esta clase


se llama NorthwindDataContext. sta clase tiene unas propiedades que
representan cada tabla modelada de la base de datos (en concreto:
Products, Categories, Customers, Orders y OrderDetails).
Como vimos en el tercer post de esta serie, podemos usar expresiones
LINQ para consultar y obtener datos usando la clase
NorthwindDataContext.LINQ to SQL traduce automticamente estas
expresiones LINQ al cdigo SQL apropiado en tiempo de ejecucin.
Por ejemplo, la siguiente expresin devuelve un objeto Product buscando el
nombre del producto:

La siguiente consulta nos devuelve todos los productos de la base de datos


que no han sido pedidos, y cuyo precio es mayor de 100 dlares:

Estamos usando la asociacin "OrderDetails" de cada producto como parte


de la consulta slo para obtener aquellos productos que no se han pedido.

Seguir los cambios y DataContext.SubmitChanges()


Cuando creamos consultas y obtenemos objetos como en los ejemplos
anteriores, LINQ to SQL estar pendiente de los cambios o actualizaciones
que les hagamos a los objetos. Podemos hacer tantas consultas y cambios
como queramos usando la clase DataContext de LINQ to SQL, sabiendo
que dichos cambios sern supervisados a la vez:
Nota: El seguimiento de cambios de LINQ to SQL ocurre en el lado del
consumidor - y NO en la base de datos. Es decir, no estamos consumiendo
ningn recurso de la base de datos mientras lo usemos, tampoco tenemos
que cambiar/instalar nada en la base de datos para que esto funcione.
Despus de realizar los cambios que queramos a los objetos que hemos
obtenido con LINQ to SQL, podemos llamar al mtodo "SubmitChanges()"
de nuestro DataContext para guardar los cambios en nuestra base de datos.
Con esto, LINQ to SQL, creara y ejecutar las sentencias SQL apropiadas
para actualizar la base de datos.
Por ejemplo, el siguiente cdigo actualiza el precio y las unidades en stock
del producto "Chai" en la base de datos:

Cuando llamamos al mtodo northwind.SubmitChanges(), LINQ to SQL


crear y ejecutar las sentencias "UPDATE" de SQL necesarias para
guardar las propiedades modificadas.
Con el siguiente cdigo iteramos sobre los productos menos populares y
caros y ponemos la propiedad "ReorderLevel" a cero.

Cuando llamamos al mtodo northwind.SubmitChanges(), LINQ to SQL crea


y ejecuta las sentencias UPDATE de SQL necesarias para modificar los
productos a los que hemos modificado la propiedad ReorderLevel.
Vemos que si no se ha modificado alguna propiedad de un Product con la
asignacin anterior, LINQ to SQL no ejecutar ninguna actualizacin para
ese objeto. Por ejemplo - si el precio del producto "Chai" era 2 dolares, y el
nmero de unidades en stock era cuatro, la llamada a SubmitChanges() no
actualizara esos valores. Slo los productos cuyo ReorderLevel no era 0 se
actualizarn.
Ejemplos de insercin y borrado
Adems de poder actualizar la base de datos, LINQ to SQL tambin nos
permite insertar y eliminar datos. Esto lo conseguimos aadiendo o
eliminando objectos de las colecciones disponibles en DataContest, y luego
llamar al mtodo SubmitChanges(). LINQ to SQL "monitorizar" esas
inserciones y borrados, y generar el cdigo SQL necesario cuando se
invoque a SubmitChanges()
Aadiendo un producto
Podemos aadir un producto a la base de datos creando un nuevo objeto
"Product", inicializando sus propiedades y aadirlo a la coleccin "Products"
de nuestro DataContext:

Cuando llamemos a SubmitChanges() se aadir una nueva fila en la tabla


de productos.
Borrando productos
De la misma forma que aadimos un nuevo producto a la base de datos
aadiendo un objeto Product a la coleccin Products del DataContext,
tambin podemos borrar productos borrndolos de esa misma coleccin:

Lo que estamos haciendo es obtener una secuencia de productos


"alternados" de la tabla, es decir, no ordenados por ninguna expresin LINQ,
y luego esa secuencia se la pasamos al mtodo RemoveAll() de la coleccin
"Products". Cuando llamamos a SubmitChanges() todos esos productos
sern borrados de la tabla
Actualizaciones y relaciones
Lo que hace que los O/RM's como LINQ to SQL sean tan flexibles es que
tambin nos permiten modelar las relaciones entre las tablas. Por ejemplo,

podemos modelar que cada producto tenga una categora, que cada pedido
tenga un detalle de pedido, asociar cada detalle de pedido con un producto,
y tener un conjunto de pedidos en cada cliente. Ya vimos cmo modelar las
relaciones en la segunda parte de esta serie de post.
LINQ to SQL nos permite aprovechar estas relaciones tanto para consultar
como para actualizar nuestros datos. Por ejemplo, con el siguiente cdigo
creamos un nuevo producto y lo asociamos con la categora "Beverages":

Estamos aadiendo el objeto producto en la coleccin de categoras de


productos. Esto indicar que hay una relacin entre dos objetos, y har que
LINQ to SQL mantenga automticamente las relaciones de clave
primaria/ajena entre los dos cuando llamemos a SubmitChanges().
Veamos otro ejemplo para ver cmo LINQ to SQL nos ayuda a mantener
limpio el cdigo referente a las relaciones entre las tablas. En el siguiente
ejemplo estamos creando un nuevo pedido para un cliente existente.
Despus de rellenar las propiedades necesarias, podemos crear dos objetos
de detalles de pedido y asociarlo a un pedido de un cliente y actualizaremos
la base de datos con todos los cambios:

Como vemos, el modelo de programacin que hemos usado para hacer


todo esto es realmente limpio y orientado a objetos.
Transacciones
Una transaccin es un servicio de la base de datos que garantiza que un
conjunto de acciones individuales van a suceder de forma atmica - es decir,
o se pueden completar todas o si hay alguna que falle, todas las demas se
descartarn, y el estado de la base de datos ser el mismo que ntes de
comenzar la transaccin.
Cuando llamemos a SubmitChanges(), las actualizaciones se mapean en
una nica transaccin. Es decir, la base de datos no tendr nunca un estado

inconsistente si hacemos muchos cambios - tanto si se hacen las


actualizaciones como si no.
Si no hay ninguna transaccin en curso, el objeto DataContext empezar
una transaccin de la base de datos para guardar las actualizaciones que
hagamos con SubmitChanges(). Pero LINQ to SQL tambin nos permite
definir explcitamente y usar nuestro propio sistema de transacciones
(introducido en la versin 2.0 de .NET). Esto hace ms fcil an integrar
cdigo LINQ to SQL con el cdigo de acceso a datos que ya tengamos.
Tambin nos permite encolar recursos que no son propios de la base de
datos en la misma transaccin - por ejemplo: podemos enviar un mensage
MSMQ, actualizar el sistema de archivos (usando el nuevo soporte
transaccional de sistemas de archivos), etc - y enlazar todas estas tareas en
una sola transaccin a la hora de actualizar la base de datos
Validacin y lgica de negocio
Una de las cosas ms importantes que los desarrolladores tienen que hacer
cuando trabajan con datos es incorporar validacin y reglas de negocio.
LINQ to SQL tiene varias formas para hacer que los desarrolladores puedan
hacer eso de forma fcil y clara.
LINQ to SQL nos permite aadir esta validacin lgica una vez. De forma
que no tendremos que repetir esa lgica en varios sitios, con lo que
conseguimos un modelo de datos ms mantenible y ms claro.
Soporte de validacin de esquemas
Cuando definimos el modelo de clases de datos con el diseador de LINQ to
SQL de VS 2008, se aadirn algunas reglas de validacin obtenidas del
esquema de las tablas de la base de datos.
Los tipos de datos de las propiedades de las clases del modelo de datos
coincidirn con el esquema de la base de datos. Con esto tendremos

errores de compilacin si intentamos asignar un booleano a un valor


decimal, o si convertirmos tipos numricos incorrectamente.
Si una columna en la base de datos est marcada como nullable, la
propiedad correspondiente que crea el diseador de LINQ to SQL ser un
tipo nullable. Las columnas marcadas como no nullables lanzarn
excepciones si no les asignamos ningun valor. LINQ to SQL tambin se
asegurar que de que los valores identidad/unicos se asignan
correctamente.
Obviamente podemos usar el diseador LINQ to SQL para sobreescribir los
valores por defecto del esquema si queremos - pero por defecto, las
tendremos automticamente sin tener que hacer nada. LINQ to SQL
tambin comprueba los valores de los parmetros de las consultas SQL, de
manera que no tendremos que preocuparnos por los ataques de inyeccin
de SQL.
Soporte para validacin personalizada de propiedades
La validacin de datos a travs de esquemas es muy til, pero no suele ser
suficiente en escenarios reales.
Imaginemos que en la base de datos Northwind tenemos una propiedad
"Phone" en la clase "Customer" que est definida en la base de datos como
nvarchar. Usando LINQ to SQL podemos escribir el siguiente cdigo para
actualizarlo con un nmero de telfono vlido:

El problema que nos encontraramos, sera que el siguiente cdigo sigue


siendo vlido desde el punto de vista de un esquema SQL (ya que sigue
siendo una cadena, no un nmero de telfono vlido).

Para no permitir que no se puedan meter nmeros de telfono errneos en


nuestra base de datos, podemos aadir una regla de validacin
personalizada a la clase Customer de nuestro modelo de datos. Es
realmente fcil, todo lo que necesitamos hacer es aadir una nueva clase
parcial a nuestro proyecto que defina el siguiente mtodo:

Este cdigo usa dos caracteristicas de LINQ to SQL:


1. Todas las clases que genera el diseador LINQ to SQL son
"parciales" - es decir, podemos aadir mtodos adicionales,
propiedades, y eventos (en archivos separados). As podemos
extender nuestro modelo de clases creada por el diseador de LINQ

to SQL con reglas de validacin y mtodos auxiliares que definamos.


No es necesario ninguna configuracin.
2. LINQ to SQL expone una serie de puntos de extensin en el modelo
de datos que podemos usar para aadir validacin lgica. Muchos de
estos puntos de extensin usan la nueva caracterstica llamada
"mtodos parciales" que viene con VB y C# en VS 2008 Beta2. Wes
Dyer el equipo de C# ha escrito un post explicando cmo va esto de
los mtodos parciales.
En nuestro ejemplo de validacin, estamos usando el mtodo parcial
OnPhoneChangin que se ejecuta cada vez que se cambia el valor de la
propiedad "Phone" de un objeto "Customer". Podemos usar este mtodo
para validar la entrada de datos (en este caso estamos usan una expresin
regular). Si todo va bien, LINQ to SQL asumir que el valor es vlido. Si hay
algn problema con el valor, podemos lanzar una excepcin en el mtodo de
validacin - que har que la asignacin no se haga.
Soporte para validacin personalizada de objetos entidad.
En el punto anterior hemos visto cmo aadir validacin a una propiedad
individual de nuestro modelo de datos. Sin embargo, algunas veces,
necesitamos/queremos validar validar multiples propiedades de un objeto.
Veamos un ejemplo, tenemos un objeto Order y queremos poner las
propiedades "OrderDate" y "RequiredDate":

Este cdigo es legal desde el punto de vista de SQL - aunque no tenga


ningn sentido la propiedad de fecha de entrega, que era para ayer.
LINQ to SQL en Beta2 nos permite aadir reglas de validacin a nivel de
entidad para corregir este tipo de errores. Podemos aadir una clase parcial
para nuestra entidad "Order" e implementar el mtodo parcial OnValidate()
que se invocar ntes de que se guarden los datos en la base de datos. De
esta forma, podemos acceder y validar todas las propiedades de nuestro
modelo de datos:

De esta forma podemos validar cualquiera de las propiedades de la entidad


(incluso obtener acceso de slo lectura a los objetos asociados), y lanzar
una excepcin si el valor es incorrecto. Cualquier excepcin lanzada desde
el mtodo OnValidate() abortar cualquier cambio que queramos hacer en la
base de datos, y deshacer todos los cambios hechos en la transaccin
actual.
Validacin en los mtodos de insercin/actualizacin/borrado.
A menudo necesitamos aadir validacin especfica en los mtodos de
insercin, actualizacin o borrado. LINQ to SQL nos lo permite aadiendo
una clase parcial que extienda a la clase DataContext e implementar
mtodos parciales para personalizar la lgica de insercin, actualizacin y

borrado de las entidades de nuestro modelo de datos. Estos mtodos sern


llamados automticamente cuando invoquemos a SubmitChanges().
Podemos aadir la validacin lgica que estimemos oportuna con estos
mtodos - y si todo va bien, LINQ to SQL continar guardando los datos en
la base de datos (llamando al mtodo de DataContext
"ExecuteDynamicXYZ").

Podemos aadir mtodos que se invocarn automticamente cuando se


vayan a crear/actualizar/borrar datos. Por ejemplo, supongamos que
queremos crear un nuevo pedido y asociarlo con un cliente existente:

Cuando llamamos a northwind.SubmitChanges(), LINQ to SQL determinar


que es necesario guardar el nuevo objeto Order, y ejecutar nuestro mtodo
parcial "InsertOrder".
Avanzado: Viendo la lista de cambios de la transaccin
Hay veces que no nos interesa aadir validacin lgica a elementos
individuales, sino que queremos ser capaces de ver toda la lista de cambios
que estn ocurriendo en una transaccin.
Desde la Beta2 de .NET 3.5, LINQ to SQL nos permite acceder a la lista de
cambios a travs del mtodo DataContext.GetChangeList(). Nos devolver
un objeto ChangeList que expone una serie de colecciones de adiciones,
borrados y modificaciones que se han hecho.
Una aproximacin que podemos hacer en algunos escenarios es crear una
clase parcial de la clase DataContext y sobreescribir su mtodo
SubmitChange(). Podemos obtener la lista de ChangeList() para las
operaciones de actualizaciones y crear cualquier validacin que queramos:

Este ejemplo es un caso de uso avanzado - pero es interesante saber que


siempre podremos extender y aprovecharnos de esta forma de las nuevas
caractersticas de LINQ to SQL.
Administrando cambios simultneos con concurrencia optimista.
Una de las cosas en las que tenemos que pensar los desarrolladores en
entornos multi-usuarios es cmo administrar las actualizaciones de los
mismos datos en la base de datos. Por ejemplo, imaginemos que tenemos
dos usuarios que obtienen un objeto product, y uno de ellos cambia el
ReorderLevel a 0 mientras que el otro lo pone a 1. Si ambos usuarios
guardan esos cambios en la base de datos, el desarrollador tiene que
decidir cmo tratar ese conflicto.
Una solucin es dejar que sea el ltimo que lo guarda - es decir, que el valor
que el primer usuario guard se perder sin que ste se de cuenta. Esta es
una solucin muy pobre (e incorrecta).
Otra solucin que permite LINQ to SQL es usar el modelo de concurrencia
optimista, es decir, LINQ to SQL detectar automticamente si el valor
original de la base de datos ha sido actualizado por alguien ntes que se

guarden los nuevos datos. LINQ to SQL nos da una lista de conflictos de
valores cambiados al desarrollador y nos permite tanto hacer lo que
queramos como avisar al usuario de la aplicacin para que nos indique el
propio usuario lo que quiere hacer.
Ya veremos en ms detalle este tema en un prximo post.
Uso de procedimientos almacenados o lgica SQL personalizada para
insertar, actualizar y borrar.
Una de las preguntas que tienen los desarrolladores (en especial los DBAs),
que suelen escribir procedimientos almacenados con SQL personalizadas,
cuando ven LINQ to SQL por primeravez es: "pero cmo podemos tener
control absoluto del SQL que se est ejecutando?".
Las buenas noticias son que LINQ to SQL tiene un modelo muy flexible que
nos permite sobreescribir el SQL que se est ejecutando, y llamar a los
procedimientos almacenados que desarrollemos para aadir, actualizar o
borrar datos.
Lo realmente increible es que podemos empezar definiendo nuestro modelo
de datos y dejar que LINQ to SQL administre las inserciones,
actualizaciones y borrados. Una vez hecho esto, podemos personalizar el
modelo de datos para que use nuestros propios procedimientos
almacenados o nuestras sentencias SQL - sin tener que cambiar nada de la
lgica de aplicacin que estamos usando para nuestro modelo de datos, ni
cambiar nada de las validaciones ni de la lgica de negocio. Esto nos da
una gran flexibilidad a la hora de construir nuestra aplicacin.
Dejaremos para otro post cmo personalizar los modelos de datos con
procedimientos almacenados o sentencias SQL.
Resumen.

Este post presenta un buen resumen sobre cmo podemos usar LINQ to
SQL para actualizar nuestra base de datos e integrar de una forma clara
validacin de datos y lgica de negocio. Creo que encontraris que LINQ to
SQL incrementa mucho la prouctividad a la hora de trabajar con datos, y nos
permite escribir cdigo orientado a objeto claro en el acceso a datos.
En prximos post veremos el nuevo control <asp:linqdatasource> de la
versin 3.5 de .NET, y hablaremos sobre lo fcil que es crear interfaces de
usuario en ASP.NET que se aprovechen de los modelos de datos de LINQ
to SQL. Tambin veremos algunos conceptos de programacin ms
especificos de LINQ to SQL sobre concurrencia optimista, carga perezosa,
herencia de mapeado de tablas, uso de procedimientos almacenados y
sentencias SQL personalizadas, y mucho ms.
Espero que sirva.
Scott.
Traducido por: Juan Mara La Ramos. Microsoft Student Partner.

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

En las ltimas semanas he escrito una serie de post sobre LINQ to SQL. Es
un ORM integrado en .NET 3.5, y nos permite modelar bases de datos
relacionales con clases de .NET. Podemos usar expresiones LINQ para
consultar a la base de datos, actualiazarla, insertar y borrar datos.
Aqu tenis los enlaces a los otros post:
Parte 1: Introduccin a LINQ to SQL
Parte 2: Definiendo el modelo de datos.
Parte 3: Consultando la base de datos
Parte 4: Actualizando la base de datos.
Parte 5: Enlazar controles de interfaz de usuario con
el ASP:LinqDatSource
En estos posts vimos cmo usar expresiones LINQ para obtener
programticamente datos de la base de datos.
En el post de hoy veremos cmo podemos usar los procedimientos
almacenados (SPROCs) y las funciones definidas por el usuario (UDFs) con
nuestro modelo LINQ to SQL. El post de hoy veremos el caso de los
SPROCs para consultar y obtener datos de la base de datos. En el siguiente
post de esta serie veremos cmo actualizar/insertar/borrar datos con
SPROCs.
SPROC o no SPROC? Esa es la cuestin
La pregunta sobre cuando usar el SQL dinmico generado por un ORM en
lugar de procedimientos almacenados creando una capa de datos es causa
de debates muy acalorados entre desarrolladores, arquitectos y DBAs.

Mucha gente ms lista que yo ha escrito sobre esto, as que no me


decantar ni por un lado ni por otro.
LINQ to SQL es muy flexible, y puede usare para crear un modelo de datos
cuyos objetos sean independientes del esquema de la base de datos, y
puede encapsular lgica de negocio y reglas de validacin que funcionan
tanto si se usa SQL generado dinmicamente o a travs de SPROCs.
En el tercer post de esta serie, hablamos sobre cmo podemos
escribir expresiones LINQ contra el modelo de LINQ to SQL como el
siguiente cdigo:

Cuando escribimos expresiones LINQ como esta, LINQ to SQL ejecutar el


SQL dinmico necesario para obtener los objetos de Product que cumplan
las restricciones.
Como aprenderemos en este post, tambin podemos mapear SPROCs en la
base de datos con la clase DataContext generada por LINQ to SQL, que nos
permitir obtener los mismo objetos de Product llamando a un procedimiento
almacenado:

Esta habilidad de poder usar tanto SQL dinmico como SPROCs con una
capa de datos limpia es muy til y nos permite una gran flexibilidad en
nuestros proyectos.
Pasos para mapear y llamar a SPROC con LINQ to SQL
En el segundo post de la serie vimos cmo usar el diseador LINQ to SQL
para crear el siguiente modelo de clases:

Fijaos en las dos partes del diseador. La de la izquierda nos permite definir
el modelo de datos que mapeara nuestra base de datos. El de la derecha
nos permite mapear SPROCs (y UDFs) en nuestro objeto DataContext, que
podemos usar en lugar del SQL dinmico para trabajar con los objetos de
nuestro modelo de datos.
Cmo mapear un SPROC en un DataContext de LINQ to SQL

Para mapear SPROCs en la clase DataContext, vamos primero al


explorador de servidores de VS 2008 y miramos a los SPROCs de nuestra
base de datos:

Haciendo doble clic en cualquier SPROC se abrir para edicin y podremos


ver el cdigo. Por ejemplo, aqu tenis el SPROC "CustOrderHist" de la
base de datos Northwind:

Para mapearlo en nuestra clase DataContext, lo arrastarmos y soltamos


desde el explorador de servidores al diseador de LINQ to SQL.
Automticamente se crear un nuevo mtodo en la clase DataContext:

Por defecto el nombre del nuevo mtodo en la clase DataContext ser el


mismo que el del SPROC, y el tipo de datos devueltos se crear
automticamente con el siguiente patron: "[NombredelSPROC]Result". Por
ejemplo: el SPROC de arriba devolver una secuencia de objetos del tipo
"CustOrderHistResult". Podemos cambiar el nombre del mtodo
seleccionndolo en el diseador y cambiarlo en la ventana de propiedades.
Como llamar a un nuevo SPROC mapeado.
Una vez que hemos seguido los pasos para mapear el SPROC en la clase
DataContext, es muy fcil de usar. Todo lo que tenemos que hacer es
llamarlo para obtener los resultados fuertemente tipados:
En VB:

En C#:

Adems de poder hacer un bucle sobre los resultados, tambin podemos


enlazar los resultados con cualquier control para mostrarlos. Por ejemplo, el
siguiente cdigo enlaza los resultados del SPROC a un control
<asp:gridview>

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

Mapeando los tipos resultado de los SPROC del modelo de datos


En el SPROC "CustOrderHist" devolva una secuencia de objetos con dos
columnas: el nombre del producto y el numero total de pedidos que el cliente
ha hecho de ese producto. El diseador LINQ to SQL defini la clase
"CustOrderHistResult" para representar los resultados.
Tambin podemos decidir mapear los resultados del SPROC a una clase de
nuestro modelo de datos (por ejemplo: a una entidad Product o Order).
Por ejemplo, tenemos el SPROC "GetProductsByCategory" en nuestra base
de datos que devuelve la siguiente informacin:

Como ntes podemos crear un mtodo "GetProductsByCategory" en la


clase DataContext que llama a este SPROC arrastrndolo al diseador de
LINQ to SQL. Ms que simplemente arrastrar el SPROC al diseador, lo
arrastraremos encima de la clase "Product":

Con esto, el mtodo "GetProductsByCategory" devolver una secuencia de


objetos "Product":

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

Para entender cmo funciona el mtodo SubmitChanges() y el seguimiento


que se hace de los cambios, y ver cmo podemos aadir lgica de negocio
a nuestro modelo de datos leed el cuarto post de esta serie.

En el prximo post de esta serie veremos tambin cmo cambiar el SQL


generado cuando insertamos/actualizamos/borramos datos con SPROCs
personalizados. Lo bueno de todo esto es que el cdigo anterior no habr
que cambiarlo si hemos configurado la clase DataContext para que use
SPROCs para las actualizaciones Manejando resultados mltiples desde SPROCs
Cuando un procedimiento almacenado puede devolver varios tipos de datos,
el tipo de resultado del SPROC en la clase DataContext no puede ser
fuertemente tipado. Por ejemplo, imaginemos el siguiente SPROC que
puede devolver un producto o un pedido dependiendo del parmetro de
entrada:

LINQ to SQL permite crear mtodos auxiliares para devolver Product o


Order aadiendo una clase parcial "NorthwindDataContext" al proyecto que
defina un mtodo (que en este caso llamaremos "VariablesShapeSample")
que invoca al SPROC y devuelve un objeto IMultipleResult:
VB:

C#:

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

C#:

Soporte de funciones definidas por el usuario (UDFs)

Adems de SPROCS, LINQ to SQL tambin soporta tanto funciones de


usuario de valores y de tablas de valores (UDFs). Una vez que aadimos un
mtodo a la clase DataContext, podemos usar estas funciones en nuestras
consultas LINQ.
Por ejemplo, veamos la funcin simple "MyUpperFunction":

Podemos arrastrar y soltar desde el explorador de servidores al diseador


de LINQ to SQL para aadirlo como un mtodo a nuestro DataContext:

Luego podemos usar esta funcin UDF en expresiones LINQ cuando


escribimos consultas contra nuestro modelo LINQ to SQL:
VB:

C#:

Si usamos el visualizador de debug de LINQ to SQL del que ya


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

Resumen
LINQ to SQL soporta poder usar procedimientos almacenados y UDFs
contra la base de datos y los integra en nuestro modelo de datos. En este

post hemos visto cmo podemos usar SPROCs para obtener datos y
pasarlo entre nuestras clases del modelo. En el prximo post veremos cmo
podemos usar SPROCS para sobreescribir la lgica de
actualizacin/insercin/borrado cuando llamamos a SubmitChanges() en el
DataContext para guardar los cambios.
Espero que sirva.
Scott.
Traducido por: Juan Mara La Ramos. Microsoft Student Partner.

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


almacenados)

En las ltimas semanas he escrito una serie de post sobre LINQ to SQL. Es
un ORM integrado en .NET 3.5, y nos permite modelar bases de datos
relacionales con clases de .NET. Podemos usar expresiones LINQ para
consultar a la base de datos, actualiazarla, insertar y borrar datos.
Aqu tenis los enlaces a los otros post:
Parte 1: Introduccin a LINQ to SQL
Parte 2: Definiendo el modelo de datos.
Parte 3: Consultando la base de datos
Parte 4: Actualizando la base de datos.
Parte 5: Enlazar controles de interfaz de usuario con
el ASP:LinqDatSource
Parte 6: Obtener datos con procedimientos almacenados.
En la sexta parte vimos cmo podemos usar procedimientos almacenados
(SPROCs) y funciones definidas por el usuario (UDFs) para consultar la
base de datos con el modelo de datos de LINQ to SQL. En el post de hoy
veremos cmo podemos usar los SPROCs para actualizar/insertar/borrar
datos de nuestra base de datos.
Para ayudar a entender esto empezaremos costruyendo una capa de datos
para la base de datos de ejemplo Northwind:
Paso 1: Crear nuestra capa de acceso a datos (sin SPROCs)
En la segunda parte de esta serie vimos cmo usar el diseador de LINQ to
SQL de VS 2008 para crear el siguiente modelo de clases:

Aadiendo reglas de validacin a nuestro modelo de clases.


Despus de definir nuestro modelo querremos aadir reglas de validacin a
nuestro modelo de datos. Podemos hacer esto aadiendo clases parciales a
nuestro proyecto y aadir las reglas de validacin en esas clases (vimos
cmo hacer esto en la cuarta parte de esta serie).
Por ejemplo, podemos aadir la lgica necesaria para asegurarnos de que
el nmero de telfono de los clientes siguen un patrn vlido, y otra para

asegurarnos de que la fecha de entrega (RequierdDate) es posterior a la


fecha actual del pedido (OrderDate). Una vez que hemos definido las clases
parciales, estos mtodos de validacin se ejecutarn cada vez que
escribamos cdigo para actualizar nuestros objetos de datos de nuestra
aplicacin:
VB:

C#:

Aadir un mtodo de ayuda GetCustomer() a nuestro DataContext


Una vez que hemos creado nuestro modelo de clases, y que le hemos
aadido reglas de validacin, podemos consultar e interactuar con los datos.
Podemos hacer esto escribiendo expresiones LINQ sobre nuestro modelo
de clases (vimos cmo hacer esto en la tercera parte de esta serie).
Tambin podemos mapear SPROCs en nuestro DataContext (esto lo vimos
en la sexta parte de la serie).
Cuando creamos una capa de datos con LINQ to SQL normalmente
querremos encapsular consultas comunes de LINQ (o SPROCs) en

mtodos auxiliares que aadiremos a la clase DataContext. Esto lo


conseguimos aadiendo una clase parcial a nuestro proyecto. Por ejemplo,
podemos aadir un mtodo llamado "GetCustomer()" que nos permita
buscar y obtener objetos Customer de la base de datos a partir del valor
CustomerID:
VB:

C#:

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


Ya tenemos una capa de datos que encapsula nuestro modelo de datos,
integra reglas de validacin, y nos permite consultar, actualizar, insertar y
borrar datos.
Veamos ahora un escenario simple usndolo para obtener un objeto
customer existente, actualizamos el ContactName y el PhoneNumber, y
creamos un nuevo objeto Order para asociarlos. El siguiente cdigo hace
todo eso en una sola transaccin. LINQ to SQL se asegura de que las
reglas de validacin se cumplen ntes de guardar nada en la base de datos:
VB:

C#:

LINQ to SQL monitoriza todas las modificaciones de los objetos que hemos
obtenido de la base de datos, y guarda los objetos que aadimos. Cuando
llamamos al mtodo DataContext.SubmitChanges(), LINQ to SQL
comprueba las reglas que hemos establecido, y genera automticamente la
SQL que actualizar el registro de Customer e insertar un nuevo registro
en la tabla Orders
Un momento - Pensaba que este post iba sobre SPROCs
Si an estais leyendo, os preguntaris dnde estn los SPROCs en este
post. Porque os estoy mostrando el cdigo de arriba que hace que se
genere una SQL dinmica? Por qu no os he enseado cmo llamar a un
SPROC para hacer las inserciones/actualizaciones/borrados todava?
La razn es que el modelo de programacin de LINQ to SQL tanto para
trabajar con objetos modelados mediante SPROC es exactamente el mismo
que con SQL dinmico. La manera en que aadimos validacin lgica es
exactamente igual (as que todas las reglas que hemos aadido a nuestro
modelo de datos se aplicarn tambin si usamos SPROCs). El cdigo

anterior que hemos usado para obtener un cliente, actualizarlo y aadir un


nuevo pedido esexactamente igual tanto si usamos SQL dinmico como si
usamos SPROCs.
Esta simetra en el modelo de programacin es muy potente ya que no
tenemos que aprender dos maneras diferentes de hacer las cosas, ni
tenemos que decidir al principio del proyecto qu tcnica usar, si SPROC o
no. Podemos empezar usando el SQL dinmico que nos da LINQ to SQL
para las consultas, inserciones, actualizaciones y borrados. Podemos aadir
reglas de validacin a nuestro modelo. Y luego podemos actualizar el
modelo de datos para usar SPROCs - o no. El cdigo y los test que
escribamos contra las clases del modelo de datos sern exctamente
iguales.
De ahora en adelante veremos cmo podemos actualizar nuestro modelo de
datos usando SPROCs para actualizar/insertar/borrar - mientras seguimos
usando las mismas reglas de validacin y trabajaremos con los mismos
cdigos anteriores.
Cmo usar SPROCs en inserciones, actualizaciones y borrados
Podemos modificar la capa de datos que estamos construyendo para que
use SPROCs, en lugar de SQL dinmico de dos maneras:
1. Usando el diseador de LINQ to SQL para configurar grficamente la
ejecucin de los SPROCs en las diferentes operaciones o
2. Aadir una clase parcial NorthwindDataContext a nuestro proyecto, y
entonces implementar los mtodos necesarios para la insercin,
borrado y actualizacin. (por ejemplo: InsertOrder, UpdateOrder,
DeleteOrder) que sern llamados cuando se realize alguna de las
operaciones asociadas. Estos mtodos parciales sern pasados a las
instancias del modelo de datos que queramos actualizar, y podemos
ejecutar tanto SPROC como cdigo SQL para guardarlo.

Cuando usemos la primera aproximacin para configurar grficamente los


SPROCs que llamaremos, por debajo se est generando el mismo cdigo
(en clases parciales que crea l solo) que escribiramos si elegimos la
segunda opcin. En general os recomiendo que usis el diseador de LINQ
to SQL para configurar los SPROCs en el 90% de los casos - y crear las
llamadas personalizadas a procedimientos almacenados en escenarios ms
avanzados.
Paso 3: Hacer otras inserciones con un SPROC
Empezaremos cambiando nuestro modelo de datos para que use SPROCs
con el objeto Order.
Primero nos vamos a la ventana de "Explorador de Servidores" (Server
Explorer) de Visual Studio, expandimos el nodo "Stored Procedures" de
nuestra base de datos, hacemos clic con el botn derecho y elegimos la
opcin "Add New Stored Procedure":

Creamos el nuevo procedimiento almacenado que llamaremos "InsertOrder"


que aade una nueva fila order a la tabla Orders:

Fijos que hemos definido el parmetro "OrderId" como un parmetro de


salida. ESto es debido a que la columna OrderID es una columna identidad
que se autoincrementa cada vez que se aade un nuevo registro. Quien
llame a este SPROC dever pasarle un valor null en ese parmetro - y el
SPROC devolver en ese parmetro el nuevo valor OrderID (llamando a la
funcin SCOPE_IDENTITY() al final del SPROC).
Despus de crear el SPROC abrimos el diseador de LINQ to SQL. De la
misma forma que vimos en la sexta parte de esta serie, podemos arrastrar y
soltar SPROCs desde la ventana "server explorer" al diseador. Esto es lo
que haremos con el nuevo SPROC que acabamos de crear:

El ltimo paso ser decirle a nuestra capa de datos que use el SPROC
InsertOrder cuano inserter un nuevo objeto Order en la base de datos. Esto
lo hacemos seleccionando la clase "Order" del diseador LINQ to SQL, y en
las propiedades clicamos el botn "..." del mtodo Insert:

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

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

El diseador de LINQ to SQL calcular una lista de parametros para el


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

nuestros modelos de datos, y podemos reutilizarlos tanto si usamos SQL o


SPROCS.
Paso 4: Actualizando los clientes con SPROCs.
Ahora vamos a modificar el objeto Customer para manejar las
actualizaciones con un SPROC.
Empezamos creando el SPROC "UpdateCustomer":

Fijaos que adems de pasar el parmetro @CustomerID, tambin tenemos


un parmetro @Original_CustomerID. La columna CustomerID de la tabla
Customers no es un campo autoincremental, y puede modificarse cuando
hagamos una actualizacin. Por tanto necesitamos ser capaces de decirle al
SPROC cual es el CustomerID original y el nuevo CustomerID. Vamos a ver
cmo mapeamos esto con el diseador de LINQ to SQL.
Veris que estamos pasando un parmetro llamado @Version (que es una
marca de tiempo) al SPROC. Es una nueva columna que he aadido a la

tabla Customers para ayudarme a controlar la concurrencia optimista.


Veremos en ms detalle este tema en otro post de esta serie - pero en
resumen es que LINQ to SQL soporta completamente la concurrencia
optimista, y nos permite usar tanto una marca de tiempo o usar valores
original/nuevo para detectar si ha habido algn cambio por parte de otro
usuario ntes de guardar los datos. Para este ejemplo usaremos una marca
de tiempo ya que hace que el cdigo sea mucho ms claro.
Una vez que tenemos nuestro SPROC, lo arrastramos y soltamos al
diseador LINQ to SQL para aadirlo como mtodo a nuestro DataContext.
Seleccionamos la clase Customer y hacemos clic en el botn "..." de la
propiedad Update:

Seleccionamos el radio button "Customize" y seleccionamos el SPROC


UpdateCustomer:

Cuando mapeamos las propiedades de los objetos Customer con los


parmetros del SPROC, veremos que tenemos que decidir si poner la
propiedad "current" en el objeto de datos, o si poner el valor original que
estaba en la base de datos antes de obtener el objeto. Por ejemplo,
tendremos que asegurarnos de que mapeamos el valor "current" de la
propiedad CustomerID en el parmetro @CustomerID, y el valor original en
el parmetro @original_customerID.

Cuando hacemos clic en OK ya esta terminado. Ahora cuando actualizemos


cualquier cliente y llamemos a SubmitChanges() se ejectuar el SPROC
UpdateCustomer en lugar de ejecutarse un SQL dinmico.
Importante: Aunque ahora estemos usando SPROC, el mtodo parcial
"OnPhoneChanging()" de la clase Customer (que creamos en el primer post
de esta serie) para validar los nmeros de telfono se seguir ejecutando de
la misma manera ntes de que se guarden los cambios. Tenemos de esta
forma una forma limpia de encapsular reglas de negocio y validacin a
nuestros modelos de datos, y podemos reutilizarlos tanto si usamos SQL
dinmico o SPROCs.
Paso 5: Usando el modelo de datos otra vez (esta vez con SPROCs)
Ahora que ya tenemos configurada nuestra capa de datos para usar SPOCs
en lugar de SQL dinmico, podemos ejecutar el mismo cdigo que vimos en
el paso 2:

Ahora las actualizacion del objeto Customer, y la insercin del objeto ORder,
se estn ejecutando a travs de SPROCs en lugar de SQL dinmico. La
lgica de validacin que definimos se siguen ejecutando como antes, y el
cdigo sigue siendo exactamente el mismo.
Apuntes avanzados cuando usamos SPROCs
Veamos unas cuantas recomendaciones tiles para escenarios con SPROC
ms avanzados con LINQ to SQL
Uso de parmetros de salida
En casos de insercin (Paso 3) hemos visto cmo podemos devolver el
nuevo valor OrderID (que es un valor identidad y autoincremental de la tabla
Orders) usando un parmetro de salida en el SPROC. No estamos limitados
a devolver slo valores de columnas identidad con SPROCs y LINQ to SQL
- en realidad podemos actualizar y devolver cualquier parmetro. Podemos
usarlo tanto para insetar como para actualizar. LINQ to SQL tomar el valor
resultado y actualizar la propiedad asociada en el modelo de dato sin que
tengamos que hacer ninguna consulta extra para refrescarlo o calcularlo de
nuevo.
Que pasa si el SPROC da un error?
Si el SPROC da un error mientras inserta, actualiza o borra un dato, LINQ to
SQL cancelar y deshar la transaccin de todos los cambios asociados a
la llamada SubmitChanges(). De manera que nos aseguramos la
consistencia de los datos.
Podemos escribir cdigo en lugar de usar el diseador para llamar a un
SPROC?
Como ya coment al principio, podemos usar tanto el diseador de LINQ to
SQL para mapear las operaciones con SPROC o podemos aadir mtodos
parciales a la clase DataContext programticamente e invocarlos nosotros

mismo. Aqu tenis un ejemplo del cdigo que deberamos escribir para
sobreescribir el mtodo UpdateCustomer de la clase NorthwindDataContext:

Este cdigo es el que fu generado con el diseador de LINQ to SQL


cuando lo usamos para mapear el SPROC y asociarlo a la operacin de
Update del objeto Customer. Podemos usarlo como un punto de partida y
aadir alguna lgica adicional para hacerlo ms personalizado (por ejemplo:
usar el valor de retorno del SPROC para lanzar excepciones
personalizadas).
Resumen
LINQ to SQL es un ORM muy flexible. Nos permite escribir cdigo limpio
orientado a objetos para obtener, acutalizar e insertar datos.
Lo mejor de todo es que nos permite disear una capa de datos realmente
limpia e independiente de cmo se guardan y cargan los datos de la base
de datos. Podemos usar SQL dinmico o SPROCs para esas operaciones.
Lo mejor es que el cdigo que use nuestra capa de datos, y todas las reglas
de negocio asociadas, sern las mismas sin importar que mtodo de
persistencia estemos usando.
En futuros post veremos ms conceptos sobre LINQ to SQL como: Herencia
simple de tablas, Carga retrasada, concurrencia optimista, y administracin
de escenarios de N-capas. ESta semana estar de vacaciones y espero
tener ms tiempo libre para escribir alguno de ellos.

Espero que sirva


Scott.
Traducido por: Juan Mara La Ramos. Microsoft Student Partner.

LINQ to SQL (Parte 8 Ejecutar consultas SQL personalizadas)

En las ltimas semanas he escrito una serie de post sobre LINQ to SQL.
LINQ to SQL es un ORM que viene con .NET 3.5, y nos permite modelar
bases de datos relacionales en clases. Podemos usar expresiones LINQ
para consultar la base de datos y tambin para actualizar, insertar y borrar
datos.
Aqu teneis los enlaces a los diferentes post de la serie:
Parte 1: Introduccin a LINQ to SQL
Parte 2: Definiendo el modelo de datos.
Parte 3: Consultando la base de datos
Parte 4: Actualizando la base de datos.
Parte 5: Enlazar controles de interfaz de usuario con
el ASP:LinqDatSource
Parte 6: Obtener datos con procedimientos almacenados.
Parte 7: Actualizando la base de datos con procedimientos
almacenados.
En los dos ltimos post vismo cmo podemos usar los procedimientos
almacenados de nuestra base de datos para consultar, insertar, actualizar y
borrar datos con el modelo de LINQ to SQL.

Una pregunta que me han hecho mucho desde que he escrito estos post es:
que pasa si quiero control total sobre las consultas SQL que usa LINQ to
SQL - pero no quiero usar SPROCs para hacerlo? En el post de hoy
veremos eso - y veremos cmo podemos usar expresiones SQL
personalizadas para que LINQ to SQL las use en lugar de las que generara
l.
Uso de expresiones LINQ con LINQ to SQL.
Supongamos que hemos usado el diseador de LINQ to SQL de VS 2008
para modelar un conjunto de clases a partir de la base de datos Northwind
(esto lo vimos en el segundo post de la serie):

En el tercer post vimos cmo podemos usar LINQ con las nuevas
caractersticas de VB y C# para consultar el modelo de clases y devolver un
conjunto de objetos que representan las filas y columnas de la base de
datos.
Por ejemplo, podemos aadir un mtodo a la clase DataContext
"GetProductsByCategory" que usa una consulta LINQ para devolver objetos
de Products de la base de datos:

VB:

c#:

Una vez definido nuestro mtodo de LINQ, podemos escribir el siguiente


cdigo para obtener productos e iterar sobre ellos:
VB:

Cuando se evala la expresin LINQ del mtodo "GetProductsByCategory",


el ORM LINQ to SQL ejectuar un SQL dinmico para obtener los datos de
la tabla Product para crear los objetos Product. Podeis usar el Visualizador
de Debug de LINQ to SQL para ver en el debugger cul es la expresin
LINQ que se ejectuar.
Uso de consultas SQL personalizadas con LINQ to SQL
En el ejemplo de arriba no tenemos que escribir ningn cdigo SQL para
consultar y obtener objetos Product fuertemente tipados. LINQ to SQL
traduce la expresin LINQ a SQL por nosotros.
Pero que pasa si queremos un control total sobre el SQL que se est
ejecutando en nuestra base de datos, y no queremos que LINQ to SQL lo
haga por nosotros? Una forma de conseguir esto es usando SPROC como
ya vimos en las partes 6 y 7 de esta serie. La otra forma es usar el mtodo
auxiliar "ExecuteQuery" de la clase DataContext y usar una expresin SQL
personalizada que le demos.
Usando el mtodo ExecuteQuery

El mtodo ExecuteQuery toma una expresin SQL como argumento , con un


conjunto de parmetros, y la ejecuta contra la base de datos (incluyendo
JOINs personalizados sobre varias tablas.
Lo que hace que ExecuteQuery sea tan til es que nos permite especifiar
cmo queremos devolver los valores de la expresin SQL. Podemos hacer
esto pasndole un parmetro tipado al mtodo o usando una versin
genrica del mtodo.
Por ejemplo, podemos cambiar el mtodo GetProductsByCategory() que
creamos ntes -con una expresin LINQ- para que use el mtodo
ExecuteQuery para ejectuar un SQL que nosotros le digamos:
VB:

C#:

Ahora podemos llamar al mtodo GetProductsByCategory() de la misma


forma que ntes:

De esta manera ser nuestra consulta SQL la que se ejecutar contra la


base de datos - y no el SQL dinmico que generara la expresin LINQ.
SQL personalizado y tracking de objetos para las actualizaciones
Por defecto cuando obtenemos objetos con LINQ to SQL, se hace un
tracking sobre los cambios que les hacemos. Si llamamos al mtodo
"SubmitChanges()" guardar los datos de forma transaccional en la base de
datos. Vismo esto en la cuarta parte de esta serie de post.
Una de las caracterstcias del metodo ExecuteQuery() es que participa en
este tracking de objetos para actualizar el modelo. Por ejemplo, podemos
escribir el siguiente cdigo para obtener todos los productos de una
categora y rebajar los precios un 10%:

Como dijimos que el tipo de resultado del ExecuteQuery en el mtodo


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

Podramos crear otro mtodo en nuestro DataContext llamado


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

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

SQL personalizadas para inserciones, actualizaciones y borrados.


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

Y si escribimos un cdigo que elimine un producto de la base de datos,


LINQ to SQL llamar al mtodo DeleteProduct - que ejecutar una SQL
personalizada en lugar del SQL dinmico que LINQ to SQL usara:

Resumen
El ORM LINQ to SQL genera y ejectua un SQL dinmico para las consultas,
actualizaciones, inserciones y borrados contra la base de datos.
Para escenarios ms avanzados, o en caso donde queramos un control total
sobre el SQL que se ejecuta, tambin podemos personalizar el ORM para
que ejecute SPROCs, o nuestras consultas SQL personalizadas. Esto nos
da una gran flexibilidad a la hora de construir y extender nuestra capa de
datos.
En prximos post veremos algunos conceptos de LINQ to SQL como:
Herenacia simple de talbas, carga a peticin, concurrencia optimista, y
escenarios de N-capas.
Espero que sirva
Scott
Traducido por: Juan Mara La Ramos. Microsoft Student Partner.

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

Nuevas caractersticas de la nueva versin


de C# Orcas
11 respuestas

La semana pasada lanzamos la versin release de la CTP de Marzo de


Visual Studio y .NET Framework Orcas. Est disponible para libre
descarga en dos versiones, una en VPC ( que permite ejecutarlo en
una mquina virtual) y otra como un instalador comn (nota: si estis
usando Vista debis aseguraros de descargaros la versin VPC, para
mquinas virtuales). Os la podis descargar aqu.
Hace unas semanas blogue sobre las mejoras (Ingls) para los
desarrolladores de ASP .NET que aporta esta release de Orcas. Si no
habis ledo este post, os lo recomiendo encarecidamente, ya
que creo que os gustarn las nuevas caractersticas que trae.
Entre todas las cosas nuevas que aporta el nuevo framework y la
herramienta, una de las cosas que creo que les gustar a los
desarrolladores (de todos los tipos de aplicaciones .NET) de Orcas son
algunas de las nuevas posibilidades que se han aadido a C# y VB.
Estos cambios en los lenguajes vienen promovidos para mejorar la
experiencia de desarrollo de manera sutil y dramtica que mejorarn
la productividad y reducirn la cantidad de cdigo que tenemos que
escribir.
En las prximas semanas voy a probar y bloguear sobre varias de
estas nuevas caractersticas de los lenguajes y ensear cmo
pueden ser usadas para obtener resultados prodigiosos.
Nueva caracterstica de C#: Propiedades automticas.
Si sois desarrolladores de C#, estaris acostumbrados a escribir
clases con propiedades bsicas como en el cdigo siguiente:
public class Person {
private string _firstName;
private string _lastName;
private int _age;
public string FirstName {
get {
return _firstName;
}
set {
_firstName = value;
}
}
public string LastName {
get {
return _lastName;
}
set {
_lastName = value;
}
}
public int Age {
get {
return _age;
}
set {
_age = value;
}

}
}Daros cuenta de que no estamos aadiendo ninguna lgica en
las propiedades Get/Set, todo lo contrario, lo que estamos haciendo
es asignar los valores a una variable. La cuestin es entonces porqu
no usamos variables en lugar de propiedades? Bueno, hay muchos
inconvenientes a la hora de exponer variables pblicas. Dos de los
problemas ms graves son: 1- No podemos hacer un databind de
forma fcil sobre variables pblicas.2- Si exponemos variables
pblicas en nuestras clases, ms tarde no es posible cambiarlas a
propiedades (por ejemplo: para aadir algn tipo de validacin en los
mtodos set) sin tener que recompilar los assemblies que dependan
de la antigua clase.El nuevo compilador de C# que viene con Orcas,
nos proporciona una forma elegante para hacer que el cdigo que
escribamos sea ms conciso mientras mantiene la flexibilidad de las
propiedades usando una nueva caracterstica conocida como
propiedades automticas. Las propiedades automticas nos
permiten evitar la declaracin manual de variables privadas y escribir
el cdigo de los mtodos get/set En lugar de eso, el compilador
puede crear automticamente las variables privadas necesarias y el
cdigo por defecto de los mtodos get/set por nosotros.Por ejemplo,
usando las propiedades automticas podemos reescribir el cdigo
anterior de la siguiente manera:public class Person {
public string FirstName {
get; set;
}
public string LastName {
get; set;
}
public int Age {
get; set;
}
} O si queremos ser ms precisos an, podemos eliminar los
espacios en blanco y llegar ms lejos de la siguiente forma:
public class Person {
public string FirstName { get; set; }
public string LastName { get; set; }
public int
Age
{ get; set; }
} Cuando el compilador de Orcas de C# se

encuentre con los


Get/Sets vacos, como en el cdigo anterior, generar
automticamente una variable privada en la clase, e implementar
las propiedades pblicas get y set para ella. El beneficio de esto es
que desde un punto de vista de tipo-contrato, la clase ser
exactamente igual que la primera implementacin de la que
hablbamos ms arriba. Esto significa que al contrario que las
variables pblicas ms adelante podemos aadir validacin lgica
en el mtodo set sin tener que cambiar ningn componente externo
que referencie a mi clase.En Bart De Smet hay una descripcin genial
sobre qu es lo que pasa por debajo cuando usamos las propiedades
automticas con la CTP release de Marzo de Orcas. Podis leerlo
en este post.Nueva caracterstica en C# y VB: Inicializadores de

objetos.Los tipos del .NET Framework confan ciegamente en el uso


de propiedades. Cuando instanciamos y usamos clases nuevas, es
muy comn escribir cdigo como este:
Person person = new Person();
person.FirstName = "Scott";
person.LastName = "Guthrie";
person.Age = 32; Habis querido

hacer esto de una forma ms


clara (o quizs en slo una lnea)?. Con los compiladores de Orcas
para C# y VB, podemos usar una caracterstica tambin genial
llamada inicializadores de objetos (en ingles: object initializers)
que nos permite hacer lo que comentamos y reescribir el cdigo
anterior de la siguiente forma:
Person person = new Person { FirstName="Scott", LastName="Gut
hrie", Age=32 };

El compilador generar automticamente el cdigo de inicializacin


necesario guardando el mismo significado semntico que en la
primera versin (ms arriba) del cdigo de ejemplo.Pero no slo nos
permite inicializar un objeto con valores simples, esta nueva
caracterstica nos permite poner valores ms complejos como
propiedades anidadas. Por ejemplo, imaginemos que en la clase
Person tambin tenemos una propiedad llamada Address del tipo
Address. Podramos escribir el siguiente cdigo para crear un objeto
del tipo Person y poner sus propiedades de la siguiente forma:
Person person = new Person {
FirstName = "Scott",
LastName = "Guthrie"
Age = 32,
Address = new Address {
Street = "One Microsoft Way",
City = "Redmond",
State = "WA",
Zip = 98052
}

En Bart De Smet tambin hay una descripcin sobre qu es lo


que pasa por debajo cuando usamos los inicializadores de objetos con
la CTP release de Marzo de Orcas. Podis leerlo en este post. Nueva
caracterstica en C# y VB: Inicializadores de colecciones de
objetos.
};

Los inicializadores de objetos estn bien, y hacen mucho ms claro


aadir objetos a colecciones de objetos. Por ejemplo, si queremos
aadir tres personas a una lista genrica de tipo Person. Podemos
escribirlo de la siguiente forma:
List<Person> people = new List<Person>();
people.Add( new Person { FirstName = "Scott", LastName = "G
uthrie", Age = 32 } );
people.Add( new Person { FirstName = "Bill", LastName = "Ga

tes", Age = 50 } );
people.Add( new Person { FirstName = "Susanne", LastName =
"Guthrie", Age = 32 } );

Usando los inicializadores de objetos slo ahorramos 12 lneas de


cdigo extra en este ejemplo en comparacin con lo que hubisemos
necesitado con el compilador de C# 2.0.
Los compiladores de Orcas para C# y VB nos permiten mucho ms, y
ahora soportan los inicializadores de colecciones (en ingls:
collection initializers) que nos permiten evitar tener varias llamadas
al mtodo Add, y ahorrarnos an ms tecleo:
List<Person> people = new
new Person { FirstName
Age = 32 },
new Person { FirstName
e = 50 },
new Person { FirstName
", Age = 32 }
};

List<Person> {
= "Scott", LastName = "Guthrie",
= "Bill", LastName = "Gates", Ag
= "Susanne", LastName = "Guthrie

Cuando el compilador encuentra un cdigo como este ltimo,


generar el cdigo necesario para aadir los diferentes elementos a
la coleccin.
Resumen
Como desarrolladores tenemos una nueva forma para hacer nuestro
cdigo ms conciso a la hora de definir objetos, inicializarlos y
aadirlos a colecciones. En ejecucin, la semntica ser exactamente
la misma que la que tenemos con la sintaxis ms larga de hoy. (As
que no tenemos que preocuparnos por cambios en el
comportamiento). No necesitamos escribir tanto por lo que nuestro
cdigo ser ms corto.
En breve escribir varios post examinando ms de cerca las nuevas
caractersticas de Orcas, como mtodos de extensin (en ingls:
Extension Methods), Lambdas, y tipos annimos. Despus me meter
con Linq, y veremos cmo aprovecha todas estas caractersticas para
facilitarnos una forma elegante para consultar e interactuar con
datos.
Espero que os haya gustado.
Scott.
Traducido por: Juan Mara La Ramos. Microsoft Student Partner

LinQ to Sql (Arquitectura de capas):


Data Label - Data Access Label - Bussines Label - UI Label

Como hemos visto, ya tenemos definida la capa de datos, ahora definiremos la


capa de negocios, en este ejemplo, la capa de negocios solo se encargar de
capturar las solicitudes de la UI y realizar las solicitudes a la capa de datos,
especficamente a la clase dalUsuario, para solicitar o realizar las acciones sobre
la entidad lnqUsuarios.

Para construir una Capa de negocios, se deben tener de antemano la mayor


cantidad de definiciones de acciones que se deben atender desde la UI (Interfaz
de Usuario), por lo cual, ya tenemos claro que haremos en la capa de datos y
debemos tener ms o menos claro cuales sern las solicitudes desde la UI.
Lo primero que haremos ser agregar a la solucin un nuevo proyecto de
bibliotecas de clase que llamaremos CapaNegocio. Si no saben como hacer esto,
deben ir a Archivo, Agregar, Nuevo proyecto y desde la ventana de proyectos
seleccionar el lenguaje y el tipo de proyecto que crearemos.
Antes de realizar la siguiente accin, vamos a generar el proyecto de biblioteca de
clase CapaDato, para ello con el botn derecho del mouse sobre el proyecto,
seleccionaremos la opcin generar.
A continuacin agregaremos una referencia desde el proyecto CapaNegocio al
proyecto CapaDato, si vemos en la carpeta bin del proyecto CapaNegocio,
veremos una dll llamada CapaDato.
Podemos construir los mtodos de esta capa, si lo desean pueden renombrar la
clase que se crea por defecto en el proyecto por brlUsuario (brl por bussiness rules
label). Como dije en la introduccin de este artculo, los nombres de clase se
repiten en los distintos niveles, as como los mtodos de las mismas, en algunos

casos. Para cualquier caso debemos crear esta clase para continuar con el
ejemplo.

En el espacio de nombre de la clase definiremos una variable que referenciar a la


clase de la capa de datos dalUsuario, de la siguiente forma:

CapaDato.dalUsuario dalUsuario = new CapaDato.dalUsuario();

Como vamos a trabajar con una solucin de UI de windows y vamos a capturar los
controles que nos enven en esta capa, lo que haremos ser agregar otra
referencia al proyecto CapaNegocio, que referenciar al espacio de
nombre System.Windows.Forms, con esto podremos definir variables de tipo de
controles de objetos.
Ahora si, piquemos cdigo!!!.

Como sabemos, debemos en nuestra interfaz, desplegar la informacin de los


usuarios, para ello vamos a crear una funcin que captura la informacin que se
enva desde la UI y realizar las acciones pertinentes, como en este ejemplo no
pasaremos los controles a la Capa de negocios voy a poner el cdigo y cada
desarrollador, segun su CI jejejeje, interpretar cada funcin.
Bromas a parte veamos las funciones que crearemos para atender las llamadas
desde la UI:

En el siguiente mtodo capturamos toda la informacin de los usuarios que se


encuentran definidos, los cuales sern desplegados de alguna forma en la UI, si
observan los mtodos de las BRL (Bussiness Rules Label) tienen los mismos
nombres que en la DAL (Data Access Label)

public List funUsuarioObtener(){


List usuario = null;
try{ usuario = dalUsuario.funUsuarioObtener(); }
catch (Exception ex) { throw ex; }

return usuario;
}

En el siguiente mtodo capturamos la informacin de un usuario en especifico


segn los criterios enviados y retorna la informacin

public CapaDato.lnqUsuario funUsuarioObtener(string usuario,


string clave) {
CapaDato.lnqUsuario cls = null;
try { cls =
this.dalUsuario.funUsuarioEspecificoObtener(usuario,
clave); }
catch (Exception ex){ throw ex; }
return cls;
}

El siguiente mtodo realiza la llamada a la insercin de un registro al mtodo


creado en la capa de datos que realizar esta accin utilizando los mtodos
dispuestos en linq to sql

public void prcUsuarioInsertar(int empleado, string usuario,


string clave) {
try { this.dalUsuario.prcUsuarioInsertar(empleado, usuario,
clave); }
catch (Exception ex) { throw ex; }
}

El siguiente mtodo realiza la llamada a la modificacin de un registro al mtodo


creado en la capa de datos que realizar esta accin utilizando los mtodos
dispuestos en linq to sql

public void prcUsuarioModificar(string usuario, string clave,


string newusuario, string newclave) {
try { this.dalUsuario.prcUsuarioModificar(usuario, clave,

newusuario, newclave); }
catch (Exception ex) { throw ex; }
}

El siguiente mtodo realiza la llamada a la eliminacin de un registro al mtodo


creado en la capa de datos que realizar esta accin utilizando los mtodos
dispuestos en linq to sql

public void prcUsuarioEliminar(string usuario, string clave)


{
try { this.dalUsuario.prcUsuarioEliminar(usuario, clave); }
catch (Exception ex) { throw ex; }
}

Ahora, cada uno puede hacer las cosas como le parezca mejor, yo solo les entrego
los lineamientos Base, ya que claramente si depuro este cdigo desde una
perspectiva de reuzabilidad, lo puedo mejorar mucho ms.
Bueno seores, el siguiente paso es crear la UI y con esto podemos probar lo que
hemos hecho, ahunque debo decir, que tal como esta este ejemplo, lo podemos
usar para web, como para windows, ya que como no estamos pasando controles
de objetos a la capa no esta personzalidada la Capa, ms bien esta habierta y se
puede reutilizar en ms ambientes.