You are on page 1of 129

Usando LINQ to SQL (1 Parte)

44 respuestas

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 video que
hice en Enero para verme construir un modelo LINQ to SQL).

Usando ese diseador LINQ to SQL puedo crear fcilmente una representacin de la base de
datos "Northwind":
El diseo de arriba define cuatro clases: Product, Category, Order y OrderDetail. Las
propiedades de cada clase mapean las columnas de cada table en la base de datos. Cada instancia
de esa clase representa una fila en las tablas.

Las flechas entre las cuatro clases de arriba representan las asociaciones/relaciones entre las
diferentes entidades. Son tpicamente modeladas como relaciones primary-key/foreign-key en la
base de datos. La direccin de las flechas en el diseador indican si la relacin es uno-a-uno o
uno-a-varios. Se aadiran propiedades fuertemente tipadas a las entidades basndose en esto. Por
ejemplo, la clase Category de arriba tiene una relacin de uno-a-varios con la clase Product. Esto
implica que tendr una propiedad "Categories" que es una coleccin de objetos Product con esa
categora. La clase Product entonces tiene una propiedad "Category" que apunta a una instancia
de la clase Category representando la categora a la que pertenece el producto.
El panel de la derecha del diseador LINQ to SQL contiene una lista de procedimientos
almacenados que interactan con nuestro modelo de base de datos. En el ejemplo de arriba
hemos aadido un SPROC (Procedimiento almacenado) "GetProductsByCategory". Como
entrada recibe un categoryID, y devuelve una secuencia de Product como resultado. Veremos
cmo llamar a este procedimiento almacenado en un ejemplo.

Entendiendo la clase DataContext

Cuando pulsis el boton "save" del diseador de LINQ to SQL, Visual Studio generar clases
.NET para representar las entidades y las relaciones de la base de datos que hemos modelado.
Por cada archivo aadido a nuestra solucin por el diseador LINQ to SQL tambin se generar
una clase DataContext. Esta clase es a traves de la cual realizaremos las consultas a las entidades
de nuestra base de datos. Esta clase tendr propiedades que representarn a cada tabla que hemos
modelado, as como mtodos para cada procedimiento almacenado que aadamos.

Por ejemplo, aqu tenis la clase NorthwindDataContext:

Ejemplos de LINQ to SQL


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

1) Consultando Products de la base de datos

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

C#:

VB:

2) Actualizando un producto en la base de datos.

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

C#:

VB:
Nota: VB en "Orcas" Beta1 no soporta Lambdas an. Pero en la Beta2 s -de forma que el cdigo
anterior se podr escribir de una forma ms concisa.

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

El siguiente cdigo muestra cmo crear una nueva categora, y entonces crear dos nuevos
productos y asociarlos a la nueva categora. Los tres son despus guardados en la base de datos.

Fijaos como no necesitamos administrar manualmente las relaciones primarykey/foreignkey.


Slo tenemos que aadir los objetos Product en la coleccin "Products" de la categora, y luego
aadir el nuevo objeto Category en la coleccin de "Categories" del DataContext, LINQ to SQL
sabr automticamente crear las PF/FK necesarias:

C#:

4)Borar productos de la base de datos.


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

C#:

VB:

5) Llamar a un procedimiento almacenado.

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

C#:
VB:

6) Obtener productos con paginado del lado del servidor

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

C#:
VB:

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)
21 respuestas

En la primera parte de la serie de post sobre LINQ to SQL habl sobre "qu es LINQ to SQL?"
y vimos por encima algunos escenarios que permite.

En aqul post pusimos unos cuantos ejemplos de cdigo donde demostrbamos cmo mejorar la
parte de datos usando LINQ to SQL:

Cmo consultar una base de datos.


Cmo actualizar filas en una base de datos
Cmo aadir y relacionar varias filas en una base de datos.
Cmo eliminar filas de la base de datos.
Cmo llamar a procedimientos almacenados.
Cmo obtener datos con paginacin en el servidor.

Mejoramos todos estos escenarios usando un modelo de clases de LINQ to SQL como ste:
En este segundo post de la serie vamos a ver en ms detalle cmo crear el modelo anterior con
LINQ to SQL.

LINQ to SQL, el diseador de LINQ to SQL, y todas las caractersticas que estamos viendo
saldrn con la versin de .NET 3.5 y en la release de Visual Studio "Orcas".

Podis seguir todos los pasos siguientes descargndo tanto Visual Studio "Orcas" Beta 1 o Visual
Web Developer Express "Orcas" Beta 1. Podis instalar las dos y usarlas sin ningn problema
con Visual Studio 2005.

Crear un nuevo modelo de datos LINQ to SQL

Podemos aadir un modelo de datos de LINQ to SQL a un projecto ASP.NET, Class Library o
Windows, con la nueva opcin "Add New Item" seleccionando "LINQ to SQL":
Seleccionando "LINQ to SQL" lanzar el diseador de LINQ to SQL, y nos permitir modelar
las clases que representen una base de datos relacional. Tambin crear una clas fuertemente
tipada "DataContext" que tendr las propiedades que representarn cualquier tabla que
modelemos de la base de datos, as como mtodos para cada procedimiento almacenado que
modelemos. Como describimos en la primera parte de esta serie de post, la clase DataContext es
el conducto principal que usaremos tanto para consultar la base de datos como para guardar los
cambios que hagamos.

Aqu tenis una captura de pantalla de un diseo LINQ to SQL ORM vaco, es lo que veris
despues de crear un nuevo modelo de datos LINQ to SQL:
Clases Entidad (Entity)

LINQ to SQL nos permite modelar clases que mapeen una base de datos. Estas clases son
tpicamente conocidas como "Clases Entidad" (en ingles "Entity Classes") y a las instancias se
las conoce como "Entidades" (en ingles "Entities"). Las clases entidad mapean a tablas de una
base de datos. Las propiedades de una clase entidad normalmente mapean las columnas de la
tabla. Cada instancia de una clase entidad representa a una fila de una tabla de la base de datos.

Las clases entidad definidas por LINQ to SQL no tienen que derivar de una clase base especfica,
lo que significa que pueden heredar de cualquier objeto que queramos. Todas las clases creadas
por el diseador de LINQ to SQL se definen como "clases parciales" - con lo que podemos,
opcionalmente, aadir propiedades adicionales, mtodos y eventos.

A diferencia de la caracterstica de DataSet/TableAdapter que aporta VS 2005, cuando usamos el


diseador de LINQ to SQL no tenemos que especificar qu consultas SQL se tiene que usar
cuando creamos el modelo de datos y la capa de acceso.

En lugar de eso, nos centramos en definir las clases entidad, cmo se mapean con la base de
datos, y las relaciones entre ellas. La implementacin del ORM de LINQ to SQL se encargar de
generar la lgica de ejecucin SQL por nosotros en tiempo de ejecucin para que podamos
interactuar y usar las entitades de datos. Podemos usar sintaxis de consultas LINQ para indicar
cmo consultar nuestro modelo de datos de forma fuertemente tipada.

Crear clases entidad de la base de datos.


Si ya tenemos un esquema de base de datos definido, podemos usarlo para crear clases entidad
LINQ to SQL.

La forma ms sencilla de conseguirlo es abrir la base de datos desde el "Server Explorer" de


Visual Studio, seleccionar las tablas y vistas (Views) que queramos modelar, y arrastrarlas al
diseador LINQ to SQL:

Cuando aadimos estas dos tablas (Categories y Products) y una vista (Invoices) de la base de
datos "Northwind" al diseador de LINQ to SQL, tendremos las siguientes clases entidad creadas
a partir del esquema de la base de datos:
Usando estas clases, podemos ejecutar todos los ejemplos de cdigo (excepto el de
procedimientos almacenados) que vimos en la primera parte de esta serie sobre LINQ to SQL.
No tenemos que aadir ningn cdigo adicional o configuracin para habilitar los escenarios de
consulta, insercin, actualizacin, borrado, y paginacin en el servidor.

Nombrado y pluralizacin

Una de las cosas de las que os daris cuenta usanto el diseador de LINQ to SQL es que
automticamente "pluraliza" los nombres de las tablas y columnas cuando crea las clases entidad
basdas en el esquema de la base de datos. Por ejemplo: la tabla "Products" del ejemplo se
resuelve en una clase "Product", y la tabla "Categories" se resuelve en la clase "Category". Este
nombrado de clases hace que vuestro modelo sea ms consistente con las convenciones de
nomenclatura de .NET, y encuentro bastante til que el diseador haga esto por mi
(especialmente cuando aadimos muchas tablas a nuestro modelo).

Si no os gusta el nombre de una clase o propiedad que el diseador ha generado, siempre podris
cambiarlo por el que queris. Podis hacerlo editanto el nombre de la entidad/propiedad en el
mismo diseador o cambiarlo en la rejilla de propiedades:
Esta habilidad de nombrado de entidades/propiedades/asociaciones es muy til en un gran
nmero de casos. En particular:

1) Cuando cambie el nombre de una tabla/columna de vuestra base de datos. Como vuestras
entidades tendrn nombres diferentes, podis decidir actualizar las reglas de mapeado y no el
cdigo de vuestra aplicacin o las consultas para usar esas nuevas tablas/columnas.

2) Cuando en el esquema de la base de datos tengais nombres que no son "limpios". Por ejemplo,
en lugar de usar "au_lname" y "au_fname" para los nombres de las propiedades en una clase
entidad, podis usar los nombres de "LastName" y "FirstName" en vuestras clases entidad y
programar con esos nombres, en vez de cambiarlo en la base de datos.

Relaciones

Cuando arrastremos objetos del "server explorer" al diseador "LINQ to SQL", Visual Studio
comprobar las relaciones de clave primaria y ajenas de los objetos, y basndose en ellas crear
relaciones por defecto entre las diferentes clases entidad que genere. Por ejemplo, cuando
aadimos las tablas Products y Categories de la base de datos NorthWind al diseador LINQ to
SQL podemos ver que se ha deducido una relacin de uno a n entre ellas (esto se indica con la
felcha del navegador):
Esta relacin har que la clase entidad Product tenga una propiedad llamada "Category" que los
desarrolladores usarn para acceder a la entidad Category para un Product dado. Tambin har
que la clase Category tenga una coleccin de "Products" que permitir a los desarrolladores
obtener todos los productos de una Category.

Si no nos gusta cmo el diseador a nombrado a la relacin, siempre podrmos cambiarlo. Slo
hay que hacer clic en la felcha en el diseador, ver las propiedades y cambiar el nombre.

Retrasar la carga

LINQ to SQL permite a los desarrolladores especificar si las propiedades de las entidades deben
precargarse o retrasarse hasta el primer acceso. Podemos personalizar las reglas de
precarga/retraso para las propiedades de las entidades seleccionando cualquier propiedad o
asociacin en el diseador, y en las propiedades poner la propiedad "Delay Loaded" a true o
false.

Por poner un ejemplo, imaginemos la clase entidad "Category" del modelo anterior. La tabla
"Categories" de la base de datos "NorthWind" tiene una columna "Picture" que contiene una
imagen (potencialmente grande) para cada categora, y slo queremos esa imagen cuando vaya a
usarla (y no cuando est haciendo una consulta para obtener los nombres de las categoras en una
lista).

Podramos configurar la propiedad Picture para que se retrase su carga seleccionandola en el


diseador de LINQ to SQL y en las propiedades poner "Delay Loaded" a true:
Nota: Adems de configurar el significado de la precarga/retraso de las entidades, podemos
sobreescribirlo va cdigo cuando hagamos consultas LINQ en las clases entidad (lo veremos en
el siguiente post de esta serie).

Usando procedimientos almacenados.

LINQ to SQL nos permite modelar procedimientos almacenados como mtodos de nuestra clase
DataContext. Por ejemplo, supongamos que hemos definido un procedimiento almacenado
simple para obtener la informacin de un producto de un categoryID:

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

Podemos usar tanto una consulta SQL (que generar una consulta SQL adhoc) o invocar el
procedimiento almacenado aadido para obtener las entidades product de la base de datos:
Usar procedimientos almacenados para actualizar/borrar/insertar datos.

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

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

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


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

Resumen

LINQ to SQL provee una forma limpia de modelar las capas de datos de nuestras aplicaciones.
Una vez que tengamos nuestro modelado de datos, podemos realizar de forma eficiente
consultas, inserciones, actualizaciones, y borrados sobre l.

Con el diseador de LINQ to SQL que viene en Visual Studio y en Visual Web Developer
Express podemos crear y administrar nuestros modelso de datos para LINQ to SQL
extremadamente rpido. El diseador LINQ to SQL tambin permite una gran flexibilidad que
nos permite personalizar el comportamiento por defecto y sobreescribir/extender el sistema para
que se adapte a nuestras necesidades.

En prximos post usaremos este modelo que hemos creado para ver en ms detalle los procesos
de consulta, inserciones, actualizaciones y borrados. En estos post tambin veremos cmo aadir
validaciones negocio/datos personalizadas a las entidades que hemos diseado.
Mike Taulty tiene una gran cantidad de videos sobre LINQ to SQL aqu, os recomiendo que los
veis. As tenis una forma de aprender viendo cmo se usa LINQ to SQL.

Espero que sirva.

Scott.

Traducido por: Juan Mara La Ramos. Microsoft Student Partner


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

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 objetos para
amoldar y definir la estructura del resultado. Y seguimos teniendo intellisense en VS 2008,
chequeo de compilacin y soporte para refactoring con estos tipos anonimos:
Paginando los resultados de la consulta.

Una de las necesidades ms comunes en entornos web es la posibilidad de hacer eficientemente


la paginancin en las interfaces de usuario. LINQ tiene dos mtodos de extensin que
permite hacer esto de forma fcil y eficiente - los mtodos Skip() y Take().

Podemos usar los mtodos Skip() y Take() para indicar que slo queremos devolver 10
objetos producto - desde la fila que le pasemos como argumento:

Fijos que no aadimos ni Skipt() ni Take() en la primera consulta - sino que lo hacemos
despus de la consulta (cuando lo enlazamos a la fuente de datos del GridView). Muchos me
preguntan "pero esto no significa que primero obtiene todos los datos de la base de datos y
luego hace la paginacin (esto es malo)?" No. La cuestin es que LINQ usa un modelo de
ejecucin en diferido, es decir, la consulta no se ejecuta hasta que se itera sobre los resultados.

Uno de los beneficios de este modelo de ejecucin en diferido es que nos permite crear
consultas en varias lneas de cdigo (lo que mejora la claridad). Tambin nos permite
crear las consultas despus de otras - lo que nos permite composiciones ms flexibles y
reutilizacin.

Una vez que tenemos el mtodo BindProduct(), podemos escribir el siguiente cdigo en
nuestra pgina para obtener el ndice de inicio de la consulta y hacer que los productos sean
paginados y mostrados en el gridview:
Esto nos dar una pgina de productos, filtrada para mostrar aquellos productos que tengan
ms de cinco pedidos, mostrando datos calculados dinmicamente, y que son paginables a
partir de una cadena de consulta:

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

Resumen

Hemos visto por encima alguna de las cosas que LINQ to SQL nos ofrece. Para aprender ms
sobre expresiones LINQ y las nuevas caractersticas de consultas que traen los compiladores de
C# y VB con VS 2008, leed estos post:

Nuevas caractersticas de la nueva versin de C# Orcas


Mtodos de extensin.
Expresiones Lambda
Sintaxis de consultas
Tipos annimos

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
43 respuestas

En las ltimas semanas he escrito una serie de post sobre LINQ to SQL. LINQ to SQL es un
O/RM(object relational mapper) integrado en la versin 3.5 del framework de .NET, y nos
permite modelar fcilmente bases de datos relacionales en clases de .NET. Podemos usar
expresiones LINQ tanto para consultar la base de datos como para actualizar, insertar y borrar
datos.

Aqu tenis los links a los tres primeros post:

Parte 1: Introduccin a LINQ to SQL


Parte 2: Definiendo el modelo de datos.
Parte 3: Consultando la base de datos

En el post de hoy veremos cmo usar el modelo de datos que hemos creado, y usarlo para
actualizar, insertar y borrar datos. Tambin veremos cmo integrar reglas de negocio y crear
lgica de validacin personalizada con nuetro modelo de datos.

Modelado de la base de datos NorthWind con LINQ to SQL

En la segundo post de esta serie, vimos cmo crear el modelo de clases con el diseador de
LINQ to SQL que trae VS 2008. Aqu tenis el modelo que creamos a partir de la base de datos
de ejemplo Northwind que usaremos en este post:
Cuando definimos el modelo definimos cinco clases: Product, Category, Customer, Order y
OrderDetail. Las propiedades de cada clase mapean las diferentes columnas de las tablas
correspondientes en la base de datos. Cada instancia de cada clase es una entidad que representa
una fila de cada tabal.

Cuando definimos nuestro modelo de datos, el diseador LINQ to SQL cre una clase llamada
DataContext que proporciona todo lo necesario para poder consultar/actualizar la base de datos.
En nuestro ejemplo, esta clase se llama NorthwindDataContext. sta clase tiene unas
propiedades que representan cada tabla modelada de la base de datos (en concreto: Products,
Categories, Customers, Orders y OrderDetails).

Como vimos en el tercer post de esta serie, podemos usar expresiones LINQ para consultar y
obtener datos usando la clase NorthwindDataContext.LINQ to SQL traduce automticamente
estas expresiones LINQ al cdigo SQL apropiado en tiempo de ejecucin.

Por ejemplo, la siguiente expresin devuelve un objeto Product buscando el nombre del
producto:

La siguiente consulta nos devuelve todos los productos de la base de datos que no han sido
pedidos, y cuyo precio es mayor de 100 dlares:

Estamos usando la asociacin "OrderDetails" de cada producto como parte de la consulta slo
para obtener aquellos productos que no se han pedido.

Seguir los cambios y DataContext.SubmitChanges()

Cuando creamos consultas y obtenemos objetos como en los ejemplos anteriores, LINQ to SQL
estar pendiente de los cambios o actualizaciones que les hagamos a los objetos. Podemos hacer
tantas consultas y cambios como queramos usando la clase DataContext de LINQ to SQL,
sabiendo que dichos cambios sern supervisados a la vez:
Nota: El seguimiento de cambios de LINQ to SQL ocurre en el lado del consumidor - y NO en la
base de datos. Es decir, no estamos consumiendo ningn recurso de la base de datos mientras lo
usemos, tampoco tenemos que cambiar/instalar nada en la base de datos para que esto funcione.

Despus de realizar los cambios que queramos a los objetos que hemos obtenido con LINQ to
SQL, podemos llamar al mtodo "SubmitChanges()" de nuestro DataContext para guardar los
cambios en nuestra base de datos. Con esto, LINQ to SQL, creara y ejecutar las sentencias SQL
apropiadas para actualizar la base de datos.

Por ejemplo, el siguiente cdigo actualiza el precio y las unidades en stock del producto "Chai"
en la base de datos:

Cuando llamamos al mtodo northwind.SubmitChanges(), LINQ to SQL crear y ejecutar las


sentencias "UPDATE" de SQL necesarias para guardar las propiedades modificadas.

Con el siguiente cdigo iteramos sobre los productos menos populares y caros y ponemos la
propiedad "ReorderLevel" a cero.

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


sentencias UPDATE de SQL necesarias para modificar los productos a los que hemos
modificado la propiedad ReorderLevel.

Vemos que si no se ha modificado alguna propiedad de un Product con la asignacin anterior,


LINQ to SQL no ejecutar ninguna actualizacin para ese objeto. Por ejemplo - si el precio del
producto "Chai" era 2 dolares, y el nmero de unidades en stock era cuatro, la llamada a
SubmitChanges() no actualizara esos valores. Slo los productos cuyo ReorderLevel no era 0 se
actualizarn.

Ejemplos de insercin y borrado

Adems de poder actualizar la base de datos, LINQ to SQL tambin nos permite insertar y
eliminar datos. Esto lo conseguimos aadiendo o eliminando objectos de las colecciones
disponibles en DataContest, y luego llamar al mtodo SubmitChanges(). LINQ to SQL
"monitorizar" esas inserciones y borrados, y generar el cdigo SQL necesario cuando se
invoque a SubmitChanges()

Aadiendo un producto

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

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

Borrando productos

De la misma forma que aadimos un nuevo producto a la base de datos aadiendo un objeto
Product a la coleccin Products del DataContext, tambin podemos borrar productos borrndolos
de esa misma coleccin:
Lo que estamos haciendo es obtener una secuencia de productos "alternados" de la tabla, es
decir, no ordenados por ninguna expresin LINQ, y luego esa secuencia se la pasamos al mtodo
RemoveAll() de la coleccin "Products". Cuando llamamos a SubmitChanges() todos esos
productos sern borrados de la tabla

Actualizaciones y relaciones

Lo que hace que los O/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 (5 Parte) Enlazar controles
de interfaz de usuario con el
ASP:LinqDatSource
23 respuestas

En las ltimas semanas he escrito una serie de post sobre LINQ to SQL. LINQ to SQL es un
O/RM que viene con la versin 3.5 del framework .NET, y nos permite modelar bases de datos
relacionales con clases de .NET. Podemos usar expresiones LINQ para consultar la base de
datos, as como actualizar, insertar y borrar datos.

Aqu tenis los links a los post anteriores:

Parte 1: Introduccin a LINQ to SQL


Parte 2: Definiendo el modelo de datos.
Parte 3: Consultando la base de datos
Parte 4: Actualizando la base de datos.

En estos post hemos visto cmo podemos usar LINQ to SQL programticamente para consultar y
actualizar nuestra base de datos.

En el post de hoy veremos el nuevo control <asp:LinqDataSource> de la nueva versin del .NET
Framework (3.5). Este control es una nueva fuente de datos para ASP.NET (como los controles
ObjectDataSource y SQLDataSource de ASP.NET 2.0) que nos va a permitir enlazar controles
de la interfaz de usuario a nuestro modelo de datos LINQ to SQL.

Aplicacin de ejemplo que construiremos.

El ejemplo que veremos se trata de una aplicacin muy simple que nos va a permitir editar los
datos de la tabla products:
La aplicacin le da al usuario las siguientes opciones de gestin:

1. Filtrado de productos por categoras.


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

La aplicacin web la implementaremos con un modelo de datos muy limpio creado con el ORM
LINQ to SQL.
Todas las reglas de negocio y las validaciones lgicas se implementarn en el la capa de datos - y
no en la capa de presentacin ni en ninguna pgina web. Con esto conseguiremos: 1) Un
conjunto consistente de reglas de negocio que sern usadas en toda la aplicacin, 2) escribiremos
menos cdigo y mejor an, no lo repetiremos y 3) podremos cambiar las reglas de negocio
cuando queramos sin tener que actualizar ese cdigo en miles de sitios en toda la aplicacin.

Tambin aprovecharemos el soporte de paginado y ordenacin de LINQ to SQL para


asegurarnos que tales operaciones no se realizan en la capa intermedia, sino en la base de datos
(es decir, slo obtendremos 10 productos de la base de datos en cada momento - no estamos
obteniendo miles de filas y ordenndolas/paginndolas en el servidor web).

Qu es el control <asp:LinqDataSource> y cmo nos ayuda?

El control <asp:LinqDataSource> es un control de ASP.NET que implementa el patrn


DataSourceControl que se introdujo con ASP.NET 2.0. Es similar a los controles
ObjectDataSource y SqlDataSource en que puede enlazar un control ASP.NET en una pgina
con la base de datos. La diferencia es que en lugar de enlazar directamente con la base de datos
(como el SqlDataSource) o a una clase genrica (como el ObjectDataSource), este control est
diseado para enlazar aun modelo de datos con LINQ.

Una de las ventajas de usar este control es que nivela la flexibilidad de los ORMs basados en
LINQ. No tenemos que definir mtodos para insercin/consulta/actualizacin y borrado para el
datasource - sino que aadimos ste control a nuestro modelo de datos, definimos con qu
entidades queremos que trabaje, y enlazamos cualquier control de ASP.NET para que trabaje con
l.

Por ejemplo, para tener un listado bsico de los productos que use las entidades Product con un
modelo de datos LINQ to SQL, slo tenemos que declarar un control <asp:linqdatasource> en
nuestra pgina que enlaze a la clase datacontext de nuestro LINQ to SQL, identificar las
entidades (por ejemplo: Products). Y ya podemos enlazar un GridView con l (modificando su
propiedad DataSourceID) para obtener un grid como el siguiente:

Sin tener que hacer nada ms, podemos ejecutar la pgina y tener un listado de los productos con
paginado y ordenacin. Podemos aadir los botones edit y delete en el grid y tener soporte
automtico para ello. No tenemos que aadir ningn mtodo, mapear ningn parmetro, ni
escribir ningn cdigo para el control <asp:LinqDataSource> para tener todas estas operaciones.
Cuando se hacen actualizaciones, el ORM se asegurar de que todas las reglas de negocio y de
validacin que hemos aadido se cumplan ntes de guardar los datos.

Importante: La belleza de LINQ y LINQ to SQL es que obviamente no slo sirven para
escenarios como el anterior - o para casos particulares para enlazar controles de interfaces de
usuario como con el LinqDataSource. Como ya hemos visto en los post anteriores, escribir
cdigo con este ORM es muy limpio. Siempre podemos escribir cdigo personalizado para
nuestras interfaces de usuario que trabajen directamente con el modelo de LINQ to SQL si
queremos o cuando nos encontremos en un escenario en el que no se pueda usar
<asp:linqdatasource>

En los siguientes pasos veremos como montar la aplicacin que hemos descrito usando LINQ to
SQL y el control <asp:LinqDataSource>

Paso 1: Definir nuestro modelo de datos

Empezaremos definiendo el modelo de datos que usaremos para representar la base de datos.

Vimos cmo definirlo en la segunda parte de estos artculos. Aqu tenis una captura de pantalla
de las clases del modelo de datos creado con el diseador de LINQ to SQL de la base de datos
"Northwind":
Volveremos sobre nuestro modelo de datos en el paso 5 de este tutorial cuando aadamos
algunas reglas de validacin de negocio. Pero para empezar usaremos el modelo de arriba.

Paso 2: Creacin de un listado bsico de productos.

Empezaremos a crear la interfaz con una pgina ASP.NET con un control <asp:gridview> con
algun estilo css:
Podramos escribir cdigo para enlazar programticamente nuestro modelo de datos al GridView
(como hicimos en la tercera parte de la serie), o podemos usar el control <asp:linqdatasource>
para enlazar el GridView al modelo de datos.

VS2008 nos permite enlazar nuestro GridView (o cualquier control de servidor ASP.NET)
grficamente a datos LINQ. Para hacerlo tenemos que pasar a la vista de diseo, seleccionar el
GridView y elegir la opcin "New Data Source ..." en "Choose Data Source":

Esto nos mostrar un cuadro de dilogo con una lista de fuentes de datos disponibles.
Seleccionamos la nueva opcin "LINQ" y le damos el nombre que queramos:
El diseador del control <asp:linqdatasource> nos mostrar las clases DataContext de LINQ to
SQL que hay disponibles (incluyendo aquellas que estn en las libreras que tengamos
referenciadas):
Seleccionaremos el modelo que creamos con el diseador de LINQ to SQL. Seleccionaremos la
tabla que queramos que sea la entidad principal con la que enlazar el grid. En nuestro caso
seleccionaremos la clase Products. Tambin seleccionamos el boton "Advanced" y habilitaremos
las actualizaciones y borrados para la fuente de datos:
Cuando hagamos clic en el botn "Finish", VS 2008 declarar un contorl <asp:linqdatasource>
en el .aspx y actualizar el gridview para que use esta fuente de datos. Tambin generar las
columnas necesarias para los diferentes campos de la clase Product:
Ahora desplegamos el "smart task" del grid view y le indicamos que queremos habilitar la
paginacin, ordenado, edicin y borrado:

Podemos pular F5 para ejecutar la aplicacin, y veremos una pgina con el listado de productos
con paginacin y ordenado:
Tambin podemos pulsar los botones "edit" o "delete" en cada fila para actualizar los datos:
Si pasamos a la vista de cdigo de la pgina, veremos las marcas que contiene. El control
<asp:linqdatasource> apunta a la clase DataContext, y a la tabla que le dijimos al principio. El
GridView tiene como fuente de datos el control <asp:linqdatasource> (en el DatasourceID) y le
indica qu columnas tienen que incluirse en el grid, cul es el texto de la cabecera, y cual es la
expresin de ordenacin:

Ahora tenemos lo bsico para empezar a trabajar con el comportamiento de esta interfaz de
usuario.

Paso 3: Limpiando las columnas.

El grid tiene muchas columnas, y dos de ellas (el SupplierId y el CategoryID) son claves ajenas,
que no conviene mostrar al usuario.

Eliminando columnas innecesarias

Empezaremos eliminando alguna de las columnas que no necesitamos. Podemos hacer esto en la
vista de cdigo(borrando la declaracin de <asp:boundfield> correspondiente) o en la vista de
diseo (haciendo clic en la columna y seleccionando la tarea "remove"). Por ejemplo, podemos
eliminar la columna "QuantityPerUnit" y ejectuar la aplicacin:

Si hemos usado el contorl <asp:ObjectDataSource> y le hemos indicado explcitamente los


parmetros de actualizacin (update) a los mtodos de actualizacin (por defecto cuando usamos
un DataSet basado en TableAdapters) una de las cosas que tenemos que hacer es cambiar la
firma de los mtodos de actualizacin del TableAdapter. Por ejemplo: si eliminamos una
columnan del grid, tenemos que modificar el TableAdapter para que soporte los mtodos de
actualizacin sin parmetros.

Con el control <asp:LinqDataSource> es que no tendramos que hacer este tipo de cambios.
Simplemente borrando (o aadiendo) una columna a la interfaz de usuario y ejecutamos la
aplicacin -no hacen falta ms cambios. Con esto conseguimos que los cambios que se hagan en
la interfaz de usuario sean mucho ms fciles, y nos permite iteraciones ms rpidas en nuestra
aplicacin.

Limpiando las columnas SupplierId y CategoryID

Hasta ahora estamos mostrando valores enteros de las claves ajenas en nuestro GridView para
los campos Supplier y Category:
Desde el punto de vista del modelo de datos es correcto, pero no desde el punto de vista del
usuario. Lo que queremos hacer es mostrar el nombre de la categora y el nombre del proveedor,
y mostrar una lista desplegable en modo edicin para que podamos cambiar estas asociaciones de
forma fcil.

Podemos cambiar el gridview para que muestre el nombre del proveedor y el de la categora en
lugar del ID, cambiando el <asp:BoundField> por un <asp:TemplateField>. Y en este
templateField aadimos el contenido que queramos para personalizar la vista de la columna.

En el cdigo siguiente aprovecharemos la capacidad de LINQ to SQL, que model este campo
como una propiedad. Es decir, posdemos enlazar de forma fcil las propiedades
Supplier.CompanyName y Category.CategoryName al grid:
Ahora ejecutamos la aplicacin y tenedremos los valores de Category y Supplier de la siguiente
forma:

Para tener una lista desplegable en estos dos campos en el modo edicin, tenemos que aadir dos
controles <asp:LinqDataSource> a la pgina. Los configuraremos para que se enlacen a las
entidades Categories y Suppliers del modelo de datos creado por LINQ to SQL:
Ahora volvemos a la columnas <asp:TemplateField> que aadimos antes y personalizaremos la
parte de edicin (especificando un EditItemTemplate). De forma que tendremos una lista
desplegable en la vista edicin, donde los valores disponibles se obtendrn de las fuentes de
datos de categoras y proveedores, y enlazaremos doblemente el valor seleccionado al SupplierId
y CategoryID de las claves ajenas:

Y ahora, cuando el usuario haga clic en el botn de edicin, se mostrar una lista con todos los
proveedores disponibles:

Y cuando salvemos los cambios se guardar el valor seleccionado en la lista desplegable.

Paso 4: Filtrando el listado de productos.


Ms que mostrar todos los productos de la base de datos, podemos actualizar la interfaz de
usuario para incluir una lista desplegable que permita al usuario filtrar los productos por una
categora particular.

Como ya aadimos un <asp:LinqDataSource> enlazada a las Categoras de nuesto modelo de


LINQ to SQL, slo tendremos que crear un nuevo control de lista desplegable y enlazarlo. Por
ejemplo:

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

Lo ltimo que queda es que cuando seleccionemos una categora se muestren los productos de
dicha categora en el gridview. Lo ms facil es seleccionar la opcin de "Configure DataSource"
en el smart task del GridView:
Con esto veremos el cuadro de dialogo para configurar el <asp:LinqDataSource> que usamos al
principio del tutorial. Seleccionamos el botn "Where" para aadir un campo de filtro al
datasource. Podemos aadir cualquier nmero de expresiones, y declarativamente asignar los
valores con los que filtrar (por ejemplo: de una querystring, de valores de formulario, de
cualquier control en la pgina, etc).

Vamos a poner un filtro de productos por su CategoryID, y obtenemos el valor con el que filtrar
de la lista desplegable que creamos antes:
Cuando le damos a "Finish", el contorl <asp:linqdatasource> se actualizar para reflejar los
cambios de filtrado:

Y cuando ejecutamos la aplicacin el usuario ser capaz de elegir una categora en la lista de
filtrado y paginar, ordenar, editar y borrar los productos de una categora:
El control <asp:LinqDataSource> aplicar las expresiones LINQ necesarias para que cuando se
ejecute contra el modelo de datos LINQ to SQL slo se obtengan los datos necesarios de la base
de datos (por ejemplo: en el grid anterior slo obtendremos 3 filas con los productos de la
categora Confection).

Tambin podemos gestionar nosotros el evento Selecting si queremos escribir expresiones LINQ
personalizadas.

Paso 5: Aadir reglas de validacin de negocio

Como ya vimos en la cuarta parte de esta serie de post, cuando definimos modelos de datos con
LINQ to SQL tendremos un conjunto de esquemas de validacin por defecto en el modelo de
clases. Es decir, si intentamos meter un valor nulo en una columna requerida, intentar asignar un
string a un entero, o asignar una valor de clave ajena en una fila que no exista, el modelo lanzar
un error y se asegurar de que la integrar de la base de datos se mantiene.

El esquema bsico de validacin es slo el primer paso, y es muy raro en la mayora de


aplicaciones reales. Normalmente necesitaremos aadir reglas adicionales a nuestro modelo de
datos. Afortunadamente con LINQ to SQL podemos aadir estas reglas de forma muy fcil (para
ms detalles sobre este tema, leed la cuarta parte de esta serie de post).

Ejemplo de escenario con reglas de validacin

Por ejemplo, supongamos una regla bsica que queramos reforzar. Queremos que un usuario de
nuestra aplicacin no pueda interrumpir un producto mientras haya unidades pedidas:
Si un usuario intenta guardar la fila anterior, queremos prevenir que ese cambio se guarde en la
base de datos y que genere un error para que el usuario lo arregle.

Aadiendo una regla de validacin al modelo de datos.

El sitio incorrecto para aadir este tipo de validacin es en la capa de presentacin. Aadirlo en
esta capa implica que esta regla ser slo vlida en un lugar concreto, y no ser automtico en
cualquier parte de la aplicacin. Distribuir la lgica de negocio en la capa de presentacin
tambin har que nuestra vida sea realmente penosa a medida que nuestra aplicacin crezca - ya
que cualquier cambio/actualizacin en nuestro negocio hara necesarios cambios de codigo en
todas partes.

El lugar correcto para este tipo de validacin es en las clases del modelo de datos de LINQ to
SQL. Como ya vimos en la cuarta parte de esta serie, todas las clases se generan por el diseador
de LINQ to SQL como clases parciales - con lo que podemos aadir
mtodos/eventos/propiedades fcilmente. El modelo de LINQ to SQL ejectuar los mtodos de
validacin que podemos implementar.

Por ejemplo, Podemos aadir una clase parcial Product a nuestro proyecto que implemente el
mtodo parcial OnValidate() que LINQ to SQL llama antes de guardar las entidades de Product.
En este mtodo podemos aadir la siguiente regla de negocio para segurarnos que los productos
no pueden tener un Reorder Level si el producto es discontinued:
Una vez que aadimos la clase anterior al proyecto LINQ to SQL, la regla anterior se
comprobar cada vez que alguien use nuestro modelo de datos e intente modificar la base de
datos. Esto se hace tanto para los productos existentes que se vayan a actualizar como para los
que se vayan a aadir nuevos.

Como el <asp:LinqDAtaSource> trabaja contra nuestro modelo de datos, cada


actualizacin/insercin/borrado pasar por esta regla de validacin antes de guardar los cambios.
No necesitamos hacer nada ms en la capa de presentacin para que se cumpla esta regla - se
comprobar cada vez que se use nuestro modelo de datos.

Aadir un manejador de errores en la capa de presentacin.

Por defecto si un usuario usa nuestro GridView para meter una combinacin no vlida de
UnitOnOrder/Discontinued, nuestro modelo LINQ to SQL lanzar una excepcin. El
<asp:LinqDataSource> capturar la excepcin y nos proporciona un evento que podemos usar
para controlarlo. Si nadie usa el evento, el contol GridView (u otro) enlazado al
<asp:LinqDataSource> capturar el error y proveer un evento para controlarlo. Si nadie controla
el error ser pasado al manejador d ela pgina, y si nadie lo controla, se le pasar al evento
Application_Error() en el archivo Global.asax. Los desarrolladores pueden hacer esto en
cualquier paso del camino para aadir la lgica de errores que queramos en la capa de
presentacin.

Para la aplicacin que estamos viendo, seguramente el mejor lugar para controlar cualquier error
de actualizacin sea en el vento rowUpdated del gridView. Este evento se ejectuar cada vez que
se actualize en nuestro datasource, y podemos ver los detalles de la excepcin si falla la
actualizacin. Podemos aadir el siguiente cdigo para comprobar si ha ocurrido un error, y
mostrar un error adecuado en caso de que ocurra:
No hemos tenido que aadir ninguna validacin lgica en nuestra interfaz de usuario. En lugar de
eso, estamos obteniendo el error que lanzamos en nuestra lgica de negocio y la estamos usando
para mostrar un mensaje adecuado al usuario (Estamos mostrando un error ms genrico).

Tambin le estamos indicando que queramos que el GridView se mantenga en el modo edicin
cuando ocurra un error - de forma que podemos evitar que el usuario pierda los cambios que
estaba haciendo, y modificar los valores y darle a "update" otra vez e intentar guardarlo.
Podemos aadir un control <asp:literal> en el "ErrorMessage" en cualquier parte de la pagina
que queramos para controlar donde queremos que se muestre el error:

Y ahora cuando intentemos actualizar un producto con valores erroneos veremos un mensaje de
error que indica cmo arreglarlo:
Lo bueno de esto es que podemos aadir o cambiar las reglas de negocio sin tener que cambiar
nada en la capa de presentacin. Las reglas de validacin, y sus mensajes correspondientes,
pueden centralizarse en un lugar en concreto del modelo de datos y se aplicarn en todas partes.

Resumen

El control <asp:LinqDataSource> nos da una forma fcil de enlazar controles de ASP.NET a


nuestro modelo de LINQ to SQL. Permite obtener/actualizar/insertar/borrar datos del modelo de
datos.

En nuestra aplicacin hemos usado el ORM LINQ to SQL para crear un modelo limpio,
orientado a objetos. Aadimos tres contorles ASP.NET a la pgina (un gridView, una lista
desplegable, y un errormessage literal), y hemos aadido tres contorles <asp:LinqDataSource>
para enlazar a Product, Category y Proveedores:
Escribimos 5 lneas de validacin lgica y 11 lineas para la gestin de errores.

El resultado final es una aplicacin web simple que permite a los usuarios filtrar los productos
por su categora, ordenar y paginar eficientemente dichos productos, editar los productos y
guardarlos (con nuestra reglas de negocio), y borrar productos del sistema (tambin con nuestra
lgica de negocio).
En prximos post veremos en profundidad algunos escenarios con concurrencia optimista, carga
a peticin, herencia de mapeado de tablas, y el uso de procedimientos almacenados y SQL
personalizados.

La prxima semana tengo pensado empezar otra serie de post sobre el control <asp:ListView> -
es un nuevo control de ASP.NET en la versin .NET 3.5. Nos permite un contorl total sobre el
cdigo generado para escenarios de datos (sin tablas, sin spans, ni estilos en linea ...), tambin
veremos el soporte para paginacin, ordenado, edicin e inserciones. Por ejemplo, podemos
usarlo en lugar del Grid con un look and feel totalmente personalizado. Lo mejor de todo,
podemos cambiar el cdigo de la pgina anterior sin tener que cambiar nada del modelo de datos,
la declaracin del <asp:linqdatasource>, o el code-behind del trato de errores.

Espero que sirva

Scott

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


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

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)
9 respuestas

En las ltimas semanas he escrito una serie de post sobre LINQ to SQL. Es un ORM integrado
en .NET 3.5, y nos permite modelar bases de datos relacionales con clases de .NET. Podemos
usar expresiones LINQ para consultar a la base de datos, actualiazarla, insertar y borrar datos.

Aqu tenis los enlaces a los otros post:

Parte 1: Introduccin a LINQ to SQL


Parte 2: Definiendo el modelo de datos.
Parte 3: Consultando la base de datos
Parte 4: Actualizando la base de datos.
Parte 5: Enlazar controles de interfaz de usuario con el ASP:LinqDatSource
Parte 6: Obtener datos con procedimientos almacenados.

En la sexta parte vimos cmo podemos usar procedimientos almacenados (SPROCs) y funciones
definidas por el usuario (UDFs) para consultar la base de datos con el modelo de datos de LINQ
to SQL. En el post de hoy veremos cmo podemos usar los SPROCs para
actualizar/insertar/borrar datos de nuestra base de datos.

Para ayudar a entender esto empezaremos costruyendo una capa de datos para la base de datos de
ejemplo Northwind:

Paso 1: Crear nuestra capa de acceso a datos (sin SPROCs)

En la segunda parte de esta serie vimos cmo usar el diseador de LINQ to SQL de VS 2008
para crear el siguiente modelo de clases:
Aadiendo reglas de validacin a nuestro modelo de clases.

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

Por ejemplo, podemos aadir la lgica necesaria para asegurarnos de que el nmero de telfono
de los clientes siguen un patrn vlido, y otra para asegurarnos de que la fecha de
entrega (RequierdDate) es posterior a la fecha actual del pedido (OrderDate). Una vez que hemos
definido las clases parciales, estos mtodos de validacin se ejecutarn cada vez que escribamos
cdigo para actualizar nuestros objetos de datos de nuestra aplicacin:

VB:

C#:
Aadir un mtodo de ayuda GetCustomer() a nuestro DataContext

Una vez que hemos creado nuestro modelo de clases, y que le hemos aadido reglas de
validacin, podemos consultar e interactuar con los datos. Podemos hacer esto escribiendo
expresiones LINQ sobre nuestro modelo de clases (vimos cmo hacer esto en la tercera parte de
esta serie). Tambin podemos mapear SPROCs en nuestro DataContext (esto lo vimos en la
sexta parte de la serie).

Cuando creamos una capa de datos con LINQ to SQL normalmente querremos encapsular
consultas comunes de LINQ (o SPROCs) en mtodos auxiliares que aadiremos a la clase
DataContext. Esto lo conseguimos aadiendo una clase parcial a nuestro proyecto. Por ejemplo,
podemos aadir un mtodo llamado "GetCustomer()" que nos permita buscar y obtener objetos
Customer de la base de datos a partir del valor CustomerID:

VB:

C#:

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


Ya tenemos una capa de datos que encapsula nuestro modelo de datos, integra reglas de
validacin, y nos permite consultar, actualizar, insertar y borrar datos.

Veamos ahora un escenario simple usndolo para obtener un objeto customer existente,
actualizamos el ContactName y el PhoneNumber, y creamos un nuevo objeto Order para
asociarlos. El siguiente cdigo hace todo eso en una sola transaccin. LINQ to SQL se asegura
de que las reglas de validacin se cumplen ntes de guardar nada en la base de datos:

VB:

C#:
LINQ to SQL monitoriza todas las modificaciones de los objetos que hemos obtenido de la base
de datos, y guarda los objetos que aadimos. Cuando llamamos al mtodo
DataContext.SubmitChanges(), LINQ to SQL comprueba las reglas que hemos establecido, y
genera automticamente la SQL que actualizar el registro de Customer e insertar un nuevo
registro en la tabla Orders

Un momento - Pensaba que este post iba sobre SPROCs

Si an estais leyendo, os preguntaris dnde estn los SPROCs en este post. Porque os estoy
mostrando el cdigo de arriba que hace que se genere una SQL dinmica? Por qu no os he
enseado cmo llamar a un SPROC para hacer las inserciones/actualizaciones/borrados todava?

La razn es que el modelo de programacin de LINQ to SQL tanto para trabajar con objetos
modelados mediante SPROC es exactamente el mismo que con SQL dinmico. La manera en que
aadimos validacin lgica es exactamente igual (as que todas las reglas que hemos aadido a
nuestro modelo de datos se aplicarn tambin si usamos SPROCs). El cdigo anterior que hemos
usado para obtener un cliente, actualizarlo y aadir un nuevo pedido es exactamente igual tanto
si usamos SQL dinmico como si usamos SPROCs.

Esta simetra en el modelo de programacin es muy potente ya que no tenemos que aprender dos
maneras diferentes de hacer las cosas, ni tenemos que decidir al principio del proyecto qu
tcnica usar, si SPROC o no. Podemos empezar usando el SQL dinmico que nos da LINQ to
SQL para las consultas, inserciones, actualizaciones y borrados. Podemos aadir reglas de
validacin a nuestro modelo. Y luego podemos actualizar el modelo de datos para usar SPROCs
- o no. El cdigo y los test que escribamos contra las clases del modelo de datos sern
exctamente iguales.

De ahora en adelante veremos cmo podemos actualizar nuestro modelo de datos usando
SPROCs para actualizar/insertar/borrar - mientras seguimos usando las mismas reglas de
validacin y trabajaremos con los mismos cdigos anteriores.

Cmo usar SPROCs en inserciones, actualizaciones y borrados

Podemos modificar la capa de datos que estamos construyendo para que use SPROCs, en lugar
de SQL dinmico de dos maneras:

1. Usando el diseador de LINQ to SQL para configurar grficamente la ejecucin de los


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

Cuando usemos la primera aproximacin para configurar grficamente los SPROCs que
llamaremos, por debajo se est generando el mismo cdigo (en clases parciales que crea l solo)
que escribiramos si elegimos la segunda opcin. En general os recomiendo que usis el
diseador de LINQ to SQL para configurar los SPROCs en el 90% de los casos - y crear las
llamadas personalizadas a procedimientos almacenados en escenarios ms avanzados.

Paso 3: Hacer otras inserciones con un SPROC

Empezaremos cambiando nuestro modelo de datos para que use SPROCs con el objeto Order.

Primero nos vamos a la ventana de "Explorador de Servidores" (Server Explorer) de Visual


Studio, expandimos el nodo "Stored Procedures" de nuestra base de datos, hacemos clic con el
botn derecho y elegimos la opcin "Add New Stored Procedure":
Creamos el nuevo procedimiento almacenado que llamaremos "InsertOrder" que aade una
nueva fila order a la tabla Orders:
Fijos que hemos definido el parmetro "OrderId" como un parmetro de salida. ESto es debido
a que la columna OrderID es una columna identidad que se autoincrementa cada vez que se
aade un nuevo registro. Quien llame a este SPROC dever pasarle un valor null en ese
parmetro - y el SPROC devolver en ese parmetro el nuevo valor OrderID (llamando a la
funcin SCOPE_IDENTITY() al final del SPROC).

Despus de crear el SPROC abrimos el diseador de LINQ to SQL. De la misma forma que
vimos en la sexta parte de esta serie, podemos arrastrar y soltar SPROCs desde la ventana "server
explorer" al diseador. Esto es lo que haremos con el nuevo SPROC que acabamos de crear:
El ltimo paso ser decirle a nuestra capa de datos que use el SPROC InsertOrder cuano inserter
un nuevo objeto Order en la base de datos. Esto lo hacemos seleccionando la clase "Order" del
diseador LINQ to SQL, y en las propiedades clicamos el botn "..." del mtodo Insert:
Hacemos clic en el botn "..." y aparecer una ventana que nos permite personalizar las
operaciones de insercin:
Fijaos cmo el modo po defecto ("Use Runtime") est configurado para usar LINQ to SQL como
generador dinmico de las SQL. Para cambiarlo seleccionamos el radio buton "Customize" y
seleccionamos el SPROC InsertOrder de la lista de SPROCS disponibles:
El diseador de LINQ to SQL calcular una lista de parametros para el SPROC que hemos
seleccionado, permitindonos mapear las propiedades de nuestra clase Order a los parmetros del
SPROC InsertOrder. Por defecto seleccionar el que ms se parezca en el nombre. Podemos
cambiarlo si queremos.

Una vez que cliquemos en OK est listo. Ahora cada vez que aadamos un nuevo pedido a
nuestro DataContext e invoquemos al mtodo SubmitChanges(), se ejecutar el SPROC
InsertOrder.

Importante: Aunque estemos usando SPROC para la persistencia, el mtodo parcial


"OnValidate()" que creamos (en la primer parte de esta serie) para encapsular las reglas de
validacin para los pedidos seguirn ejecutndose antes de realizar cualquier cambio. Es decir,
tenemos una forma limpia de encapsular la lgica de negocio y las reglas de validacin en
nuestros modelos de datos, y podemos reutilizarlos tanto si usamos SQL o SPROCS.

Paso 4: Actualizando los clientes con SPROCs.

Ahora vamos a modificar el objeto Customer para manejar las actualizaciones con un SPROC.
Empezamos creando el SPROC "UpdateCustomer":

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


@Original_CustomerID. La columna CustomerID de la tabla Customers no es un campo
autoincremental, y puede modificarse cuando hagamos una actualizacin. Por tanto necesitamos
ser capaces de decirle al SPROC cual es el CustomerID original y el nuevo CustomerID. Vamos
a ver cmo mapeamos esto con el diseador de LINQ to SQL.

Veris que estamos pasando un parmetro llamado @Version (que es una marca de tiempo) al
SPROC. Es una nueva columna que he aadido a la tabla Customers para ayudarme a controlar
la concurrencia optimista. Veremos en ms detalle este tema en otro post de esta serie - pero en
resumen es que LINQ to SQL soporta completamente la concurrencia optimista, y nos permite
usar tanto una marca de tiempo o usar valores original/nuevo para detectar si ha habido algn
cambio por parte de otro usuario ntes de guardar los datos. Para este ejemplo usaremos una
marca de tiempo ya que hace que el cdigo sea mucho ms claro.

Una vez que tenemos nuestro SPROC, lo arrastramos y soltamos al diseador LINQ to SQL para
aadirlo como mtodo a nuestro DataContext. Seleccionamos la clase Customer y hacemos clic
en el botn "..." de la propiedad Update:
Seleccionamos el radio button "Customize" y seleccionamos el SPROC UpdateCustomer:
Cuando mapeamos las propiedades de los objetos Customer con los parmetros del SPROC,
veremos que tenemos que decidir si poner la propiedad "current" en el objeto de datos, o si poner
el valor original que estaba en la base de datos antes de obtener el objeto. Por ejemplo,
tendremos que asegurarnos de que mapeamos el valor "current" de la propiedad CustomerID en
el parmetro @CustomerID, y el valor original en el parmetro @original_customerID.

Cuando hacemos clic en OK ya esta terminado. Ahora cuando actualizemos cualquier cliente y
llamemos a SubmitChanges() se ejectuar el SPROC UpdateCustomer en lugar de ejecutarse un
SQL dinmico.

Importante: Aunque ahora estemos usando SPROC, el mtodo parcial "OnPhoneChanging()" de


la clase Customer (que creamos en el primer post de esta serie) para validar los nmeros de
telfono se seguir ejecutando de la misma manera ntes de que se guarden los cambios.
Tenemos de esta forma una forma limpia de encapsular reglas de negocio y validacin a nuestros
modelos de datos, y podemos reutilizarlos tanto si usamos SQL dinmico o SPROCs.

Paso 5: Usando el modelo de datos otra vez (esta vez con SPROCs)

Ahora que ya tenemos configurada nuestra capa de datos para usar SPOCs en lugar de SQL
dinmico, podemos ejecutar el mismo cdigo que vimos en el paso 2:

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

Apuntes avanzados cuando usamos SPROCs

Veamos unas cuantas recomendaciones tiles para escenarios con SPROC ms avanzados con
LINQ to SQL

Uso de parmetros de salida

En casos de insercin (Paso 3) hemos visto cmo podemos devolver el nuevo valor OrderID (que
es un valor identidad y autoincremental de la tabla Orders) usando un parmetro de salida en el
SPROC. No estamos limitados a devolver slo valores de columnas identidad con SPROCs y
LINQ to SQL - en realidad podemos actualizar y devolver cualquier parmetro. Podemos usarlo
tanto para insetar como para actualizar. LINQ to SQL tomar el valor resultado y actualizar la
propiedad asociada en el modelo de dato sin que tengamos que hacer ninguna consulta extra para
refrescarlo o calcularlo de nuevo.

Que pasa si el SPROC da un error?

Si el SPROC da un error mientras inserta, actualiza o borra un dato, LINQ to SQL cancelar y
deshar la transaccin de todos los cambios asociados a la llamada SubmitChanges(). De manera
que nos aseguramos la consistencia de los datos.

Podemos escribir cdigo en lugar de usar el diseador para llamar a un SPROC?

Como ya coment al principio, podemos usar tanto el diseador de LINQ to SQL para mapear
las operaciones con SPROC o podemos aadir mtodos parciales a la clase DataContext
programticamente e invocarlos nosotros mismo. Aqu tenis un ejemplo del cdigo que
deberamos escribir para sobreescribir el mtodo UpdateCustomer de la clase
NorthwindDataContext:

Este cdigo es el que fu generado con el diseador de LINQ to SQL cuando lo usamos para
mapear el SPROC y asociarlo a la operacin de Update del objeto Customer. Podemos usarlo
como un punto de partida y aadir alguna lgica adicional para hacerlo ms personalizado (por
ejemplo: usar el valor de retorno del SPROC para lanzar excepciones personalizadas).

Resumen

LINQ to SQL es un ORM muy flexible. Nos permite escribir cdigo limpio orientado a objetos
para obtener, acutalizar e insertar datos.

Lo mejor de todo es que nos permite disear una capa de datos realmente limpia e independiente
de cmo se guardan y cargan los datos de la base de datos. Podemos usar SQL dinmico o
SPROCs para esas operaciones. Lo mejor es que el cdigo que use nuestra capa de datos, y todas
las reglas de negocio asociadas, sern las mismas sin importar que mtodo de persistencia
estemos usando.
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)
4 respuestas

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 )
13 respuestas

En las ltimas semanas he escrito una serie de post sobre LINQ to SQL. LINQ to SQL es un
ORM que viene con .NET 3.5, y nos permite modelar bases de datos relacionales en clases.
Podemos usar expresiones LINQ para consultar la base de datos y tambin para actualizar,
insertar y borrar datos.

Aqu tenis los enlaces a los diferentes post de la serie:

Parte 1: Introduccin a LINQ to SQL


Parte 2: Definiendo el modelo de datos.
Parte 3: Consultando la base de datos
Parte 4: Actualizando la base de datos.
Parte 5: Enlazar controles de interfaz de usuario con el ASP:LinqDatSource
Parte 6: Obtener datos con procedimientos almacenados.
Parte 7: Actualizando la base de datos con procedimientos almacenados.
Parte 8: Ejecutar consultas SQL personalizadas.

En la quinta parte vimos el control <asp:LinqDataSource> de .NET 3.5 y hablamos sbre cmo
podemos enlazar controles de ASP.NET a LINQ to SQL. Tambin vimos cmo usarlo con el
control <asp:ListView> (El control asp:ListView (Parte 1 - Creacin de una pgina de listado de
productos con una CSS limpia))

En ambos artculos las consultas que hacamos eran relativamente sencillas (la clausula where se
ejecutaba sobre una tabla simple). En el post de hoy veremos cmo usar toda la potecia de las
consultas de LINQ con el control LinqDataSource, y veremos cmo usar cualquier expresion
LINQ to SQL con l.

Pequea recapitulacin: <asp:LinqDataSource> con una sentencia Where.

En estos dos post vimos cmo usar el filtro del control LinqDatasource para declarar un filtro en
un modelo LINQ to SQL.

Por ejemplo, supongamos que hemos creado un modelo LINQ to SQL de la base de datos
Northwind (que ya vimos en la segunda parte de esta serie), podramos declarar un control
<asp:LinqDataSource> en la pgina con un filtro <where> que devuelve aquellos productos de
una categora dada. (especificada a partir del valor "categoryid").
Luego, podemos enlazar un <asp:gridView> a este datasource y habilitar la paginacin, edicin y
ordenacin.:

Cuando ejecutamos la pgina anterior tendremos un GridView que soportar automticamente la


ordenacin, paginacin y edicin sobre el modelo de Produt:
Usando los parmetros del <where> de esta forma funciona muy bien en escenarios tpicos. Pero
qu pasa si que el filtrado de Product sea ms complejo? Por ejemplo, Si slo queremos
mostrar los productos suministrados por un conjunto dinmico de paises?

Uso del evento Selecting del <asp:LinqDataSource>

En consultas personalizadas podemos implementar un manejador de eventos para el evento


"Selecting" en el control <asp:LinqDataSource>. Con este manejador podemos escribir el cdigo
que queramos para obtener los datos. Esto lo podemos hacer con una expresin LINQ to SQL, o
llamar a un procedimiento almacenado o usar una expresin SQL personalizada. Una vez que
obtenemos la secuencia de datos, todo lo que tenemos que hacer es asignar la propiedad "Result"
al objeto LinqDataSourceSelectEventArgs. El <asp:LinqDataSource> usar esta secuencia como
los datos con los que trabajar.

Por ejemplo, aqu tenis una consulta LINQ to SQL que obtiene aquellos productos de los
proveedores de un conjunto de pases:

VB:
C#:

Nota: No tenemos que escribir la consulta en el cdigo del manejador. Una solucin ms limpia
sera encapsularla en un mtodo de ayuda al que podramos llamar desde el propio manejador.
Esto lo vimos en la parte 8 de esta serie (usando el mtodo GetProductsByCategory).

Ahora, cuando ejecutemos la pgina usando este manejador, slo obtendremos los productos de
los proveedores de ciertos pases:
Una de las cosas ms interesantes es que la paginacin y la ordenacin siguen funcionando en
nuestro GridView - aunque estemos usando el evento Selecting. Esta lgica de paginacin y
ordenacin ocurre en la base de datos - es decir, slo devolvemos los 10 productos de la base de
datos que necesitamos para el ndice actual del GridView (supereficiente).

Os estaris preguntando - cmo es posible que tengamos una paginacin y ordenacin eficiente
incluso cuando lo hacemos con un evento personalizado?. La razn es que LINQ usa el modelo
de ejecucin en diferido - es decir, la consulta no se ejecuta hasta que intentamos iterar sobre los
resultados. Uno de los beneficios de este modelo es que nos permite componer consultas con
otras consultas, y aadirles "comportamiento". Podis leer ms sobre esto en la tercera parte de la
serie LINQ to SQL.

En nuestro evento "Selecting" estamos declarando una consulta LINQ personalizada que
queremos ejecutar y luego se la asignamos a la propiedad "e.Result". Pero an no la hemos
ejecutado (ya que no hemos iterado sobre los resultados o llamado a los mtodos ToArray() o
ToList()). El LINQDataSource es capaz de aadir automticamente los operadores Skip() y
Take() al aconsulta, as como aplicarle una expresin "orderby" -- siendo todos estos valores
calculados automticamente a partir del ndice de pgina y las preferencias de ordenacin del
GridView. Slo entonces el LINQDataSource ejecuta la expresin LINQ y obtiene los datos.
LINQ to SQL se encarga de que la lgica de ordenacin y paginado se haga en la base de datos -
y que slo se devuelvan 10 filas de productos.

Fijos cmo podemos seguir usando el GridView para editar y borrar datos, incluso cuando
usamos el evento "Selecting" del LINQDataSource:

El soporte de edicion/borrado funcionar mientras que el evento Selecting asigne la secuencia de


resultados a la propiedad Result y sean objetos entidad (por ejemplo: una secuencia de Product,
Supplier, Category, Order, etc). El LinqDataSource administrar los casos en el que los controles
hagan actualizaciones sobre ellos.
Para leer mas sobre cmo funcionan las actualizaciones con LINQ to SQL, leed la parte cuatro
de esta serie, y luego la parte quinta para ver las Updates en acccin.

Realizano proyecciones de consultas personalizadas con el evento Selecting.

Una de las caractersticas ms poderosas de LINQ es la habilidad de "formar" o "proyectar"


datos. Podemos hacer esto en una expresin LINQ to SQL para indicar que queremos obtener
slo un subconjunto de valores de una entidad, y/o calcular nuevos valores dinmicamente al
vuelo con expresiones personalizadas que definamos. Para leer ms sobre esto leed la tercera
parte de la serie.

Por ejemplo, podemos modificar el evento "Selecting" para calcular un GridView para que
muestre un subconjunto de informacin de Product. En el grid queremo mostrar el ProductID,
ProductName, Product UnitPrice, el nmero de pedidos de ese producto, y el total de pedidos de
ese producto. Podemos calcular estos dos ltimos campos con la siguiente expresin LINQ:

VB:

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

El resultado de esta expresin LINQ cuando lo enlazamos al GridView es el siguiente:


Fijaos que la paginacin y la ordenacin sigue funcionando en el GridView - aunque estemos
usando una proyeccin de LINQ para los datos.

Una caracterstica que no funcionar con las proyecciones es el soporte para la edicin. Esto es
debido a que estamos haciendo una proyeccin personalizada en el mtodo Selecting, y el
LINQDataSource no tiene forma de saber cmo actualizar la entidad. Si queremos aadir soporte
para la edicin en este caso, tendremos que crear un control ObjectDataSource (al que le
pondremos un mtodo Update personalizado para contorlarlos), o hacer que el usuario navegue a
una nueva pgina para hacer la actualizacin - y mostrar un DetailsView o FormView enlazado a
la entidad Producto para la edicin (y no intentar hacerlo en el grid).

Resumen

Podemos realizar consultas personalizadas sobre el modelo LINQ to SQL usando el soporte
integrado de filtrado del LINQDataSource.

Para habilitar opiciones de filtrado ms avanzadas, usaremos el mtodo Selecting del


LINQDataSource. Esto no permitir crear la lgica que queramos para obtener y filtrar datos
LINQ to SQL. Podemos llamar a mtodos para obtener los datos, usar Expresiones LINQ, llamar
a procedimientos almacenados o invocar una expresin SQL personalizada para hacer esto.

Espero que sirva.

Scott.

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