martes, 11 de mayo de 2010

Linq To Dataset: Mostrar el contenido de varias tablas en un Datagrid

Hola,
En el articulo anterior sobre WPF vimos como aprovecharnos de Las datarelations y los dataset tipados para mostrar en una datagrid datos de varias tablas y mostrar fácilmente detalles relacionados con el elemento seleccionado en la datagrid.
Hoy vamos a hacer algo parecido en Windows Forms, usando Linq para mostrar el contenido de varias tablas en una datagrid de forma sencilla, tengamos o no nuestros datasets tipados.

Para ello vamos a crear un dataset no tipado con 3 tablas: Order, Details y Products, con los siguientes campos:
OrderDetailsProducts
orderIDorderIDproductID
orderDateproductIDproductDesc
quantityprice
Para emular el comportamiento de un método que lea los datos de una base de datos, he creado un método llamado DevuelveDatos con el siguiente código:
Public Function DevuelveDatos() As DataSet
'Creamos el nuevo dataset con 3 tablas.
Dim ds As New DataSet
ds.Tables.Add("Order")
ds.Tables.Add("Details")
ds.Tables.Add("Products")

'Creamos las columnas de las tablas.
'Order:
ds.Tables("Order").Columns.Add("orderID")
ds.Tables("Order").Columns.Add("orderDate")

'Details
ds.Tables("Details").Columns.Add("orderID")
ds.Tables("Details").Columns.Add("productID")
ds.Tables("Details").Columns.Add("quantity")

'Products
ds.Tables("Products").Columns.Add("productID")
ds.Tables("Products").Columns.Add("productDesc")
ds.Tables("Products").Columns.Add("price")

'Insertamos registros en las tablas.
For i As Integer = 1 To 10
ds.Tables("Order").Rows.Add(New String() {i.ToString, Date.Now})
For j As Integer = 1 To 10
ds.Tables("Details").Rows.Add(New String() {i.ToString, j.ToString, i.ToString})
Next
ds.Tables("Products").Rows.Add(New String() {i.ToString, "Producto " + i.ToString, New Random(25 * i).Next.ToString})
Next
ds.AcceptChanges()
Return ds
End Function




Bien, en el evento form load del formulario de ejemplo cargamos los datos y posteriormente los mostramos en la datagrid usando Linq To Dataset:


Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
Dim ds As New DataSet

'Buscamos nuestros datos.
ds = DevuelveDatos()

'Asignamos los datos a nuestra datagrid.
DataGridView1.DataSource = (
From roworden As DataRow In ds.Tables("Order") 
Join rowdetalles As DataRow In ds.Tables("Details") 
On roworden.Field(Of String)("orderID") Equals rowdetalles.Field(Of String)("orderID") 
Join rowproductos As DataRow In ds.Tables("Products") 
On rowdetalles.Field(Of String)("productID") Equals rowproductos.Field(Of String)("productID")
Select New With 
{ 
.CodOrden = roworden.Field(Of String)("orderID"), 
.FechaOrden = roworden.Field(Of String)("orderDate"), 
.Producto = rowproductos.Field(Of String)("productDesc"), 
.Cantidad = rowdetalles.Field(Of String)("quantity"), 
.PrzUnidad = rowproductos.Field(Of String)("price"), 
.Total = .Cantidad * .PrzUnidad 
} 
).ToList

End Sub


Bien, aquí está el Linq To Dataset, un lenguaje muy sencillo de entender para todos los que hayan usado SQL alguna vez, vamos a explicarlo por partes:




Primero creamos un objeto Datarow de nuestra tabla maestra Order:


From roworden As DataRow In ds.Tables("Order")


Ahora, de forma muy similar a SQL, usamos la instrucción Join de Linq para unir la tabla de detalles, creamos un objeto Datarow para nuestra tabla Detalles e indicamos los campos de ambas rows (roworden y rowdetalles) usados para unirlas:


Join rowdetalles As DataRow In ds.Tables("Details")
On roworden.Field(Of String)("orderID") Equals rowdetalles.Field(Of String)("orderID")


Y de la misma forma lo hacemos con la tabla products, creando un objeto rowproductos:


Join rowproductos As DataRow In ds.Tables("Products")
On rowdetalles.Field(Of String)("productID") Equals rowproductos.Field(Of String)("productID")


Bien, una vez que hemos indicado los joins de nuestras tablas solo nos queda seleccionar el resultado de nuestra consulta Linq To Dataset, esto lo hacemos con el Select:


Select New With
{
.CodOrden = roworden.Field(Of String)("orderID"),
.FechaOrden = roworden.Field(Of String)("orderDate"),
.Producto = rowproductos.Field(Of String)("productDesc"),
.Cantidad = rowdetalles.Field(Of String)("quantity"),
.PrzUnidad = rowproductos.Field(Of String)("price"),
.Total = .Cantidad * .PrzUnidad
}


la primera parte (.NombreCampo) es el nuevo campo que queremos crear en el resultado, puede ser el mismo nombre que el campo de origen o un nombre diferente y simplemente lo igualamos al campo del objeto row que deseemos. Si nuestro Dataset estuviese tipado, en vez de usar Field(Of T) podríamos usar el nombre de nuestro campo directamente. Por último el campo total es un campo calculado a partir de otros campos anteriores.


El Resultado de Nuestro programa es este:


screenshot


Espero que os sea útil a continuación teneis el código fuente para descargarlo, un gran saludo y Happy Coding!


No hay comentarios:

Publicar un comentario en la entrada