Linq to sql 9
Click here to load reader
description
Transcript of Linq to sql 9
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 también para actualizar, insertar y borrar datos.
Aquí tenéis los enlaces a los diferentes post de la serie:
Parte 1: Introducción 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 cómo podemos enlazar
controles de ASP.NET a LINQ to SQL. También vimos cómo usarlo con el control <asp:ListView> (El control
asp:ListView (Parte 1 - Creación de una página de listado de productos con una CSS limpia))
En ambos artículos las consultas que hacíamos eran relativamente sencillas (la clausula where se ejecutaba sobre una
tabla simple). En el post de hoy veremos cómo usar toda la potecia de las consultas de LINQ con el control
LinqDataSource, y veremos cómo usar cualquier expresion LINQ to SQL con él.
Pequeña recapitulación: <asp:LinqDataSource> con una sentencia Where.
En estos dos post vimos cómo 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), podríamos declarar un control <asp:LinqDataSource> en la página con un filtro
<where> que devuelve aquellos productos de una categoría dada. (especificada a partir del valor "categoryid").
Luego, podemos enlazar un <asp:gridView> a este datasource y habilitar la paginación, edición y ordenación.:
Cuando ejecutamos la página anterior tendremos un GridView que soportará automáticamente la ordenación,
paginación y edición sobre el modelo de Produt:
Usando los parámetros del <where> de esta forma funciona muy bien en escenarios típicos. Pero ¿qué pasa si que el
filtrado de Product sea más complejo? Por ejemplo, ¿Si sólo queremos mostrar los productos suministrados por un
conjunto dinámico 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 código que queramos para obtener los datos. Esto lo
podemos hacer con una expresión LINQ to SQL, o llamar a un procedimiento almacenado o usar una expresión 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í tenéis una consulta LINQ to SQL que obtiene aquellos productos de los proveedores de un conjunto
de países:
VB:
C#:
Nota: No tenemos que escribir la consulta en el código del manejador. Una solución más limpia sería encapsularla en
un método de ayuda al que podríamos llamar desde el propio manejador. Esto lo vimos en la parte 8 de esta serie
(usando el método GetProductsByCategory).
Ahora, cuando ejecutemos la página usando este manejador, sólo obtendremos los productos de los proveedores de
ciertos países:
Una de las cosas más interesantes es que la paginación y la ordenación siguen funcionando en nuestro GridView -
aunque estemos usando el evento Selecting. Esta lógica de paginación y ordenación ocurre en la base de datos - es
decir, sólo devolvemos los 10 productos de la base de datos que necesitamos para el índice actual del GridView
(supereficiente).
Os estaréis preguntando - ¿cómo es posible que tengamos una paginación y ordenación eficiente incluso cuando lo
hacemos con un evento personalizado?. La razón es que LINQ usa el modelo de ejecución 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 añadirles "comportamiento". Podéis leer más 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 aún no la hemos ejecutado (ya que no hemos iterado sobre los resultados
o llamado a los métodos ToArray() o ToList()). El LINQDataSource es capaz de añadir automáticamente los
operadores Skip() y Take() al aconsulta, así como aplicarle una expresión "orderby" -- siendo todos estos valores
calculados automáticamente a partir del índice de página y las preferencias de ordenación del GridView. Sólo entonces
el LINQDataSource ejecuta la expresión LINQ y obtiene los datos. LINQ to SQL se encarga de que la lógica de
ordenación y paginado se haga en la base de datos - y que sólo se devuelvan 10 filas de productos.
Fijáos cómo 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 cómo funcionan las actualizaciones con LINQ to SQL, leed la parte cuatro de esta serie, y luego la
parte quinta para ver las Updates en accción.
Realizano proyecciones de consultas personalizadas con el evento Selecting.
Una de las características más poderosas de LINQ es la habilidad de "formar" o "proyectar" datos. Podemos hacer esto
en una expresión LINQ to SQL para indicar que queremos obtener sólo un subconjunto de valores de una entidad, y/o
calcular nuevos valores dinámicamente al vuelo con expresiones personalizadas que definamos. Para leer más 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
información de Product. En el grid queremo mostrar el ProductID, ProductName, Product UnitPrice, el número de
pedidos de ese producto, y el total de pedidos de ese producto. Podemos calcular estos dos últimos campos con la
siguiente expresión LINQ:
VB:
C#:
Nota: El método Sum para calcular el Revenue es un ejemplo de un método de extensión. La función es una expresión
lambda. El tipo de resultados creados de la consulta LINQ es un tipo anónimo - ya que el tipo es inferido de la
consulta. Métodos de extensión, expresiones Lambda, y los tipos anónimos son nuevas características de VB y C# en
VS 2008.
El resultado de esta expresión LINQ cuando lo enlazamos al GridView es el siguiente:
Fijaos que la paginación y la ordenación sigue funcionando en el GridView - aunque estemos usando una proyección
de LINQ para los datos.
Una característica que no funcionará con las proyecciones es el soporte para la edición. Esto es debido a que estamos
haciendo una proyección personalizada en el método Selecting, y el LINQDataSource no tiene forma de saber cómo
actualizar la entidad. Si queremos añadir soporte para la edición en este caso, tendremos que crear un control
ObjectDataSource (al que le pondremos un método Update personalizado para contorlarlos), o hacer que el usuario
navegue a una nueva página para hacer la actualización - y mostrar un DetailsView o FormView enlazado a la entidad
Producto para la edición (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 más avanzadas, usaremos el método Selecting del LINQDataSource. Esto no
permitirá crear la lógica que queramos para obtener y filtrar datos LINQ to SQL. Podemos llamar a métodos para
obtener los datos, usar Expresiones LINQ, llamar a procedimientos almacenados o invocar una expresión SQL
personalizada para hacer esto.