LINQ to Entities y Visual Basic 2008 – Parte 2
LINQ to Entities (L2E)
Parte 2: Resolviendo problemas con el volcado de datos a un control DataGridView
Resumen general de lo publicado sobre LINQ hasta el momento:
Información general sobre LINQ
LINQ to Objects
LINQ to XML
LINQ to DataSet
LINQ to SQL
LINQ to Entities
Introducción
En la anterior entrega de LINQ to Entities os comentaba como trabajar con datos y LINQ to Entities de una manera introductoria.
Era un sencillo ejemplo que quería que sirviera de patrón o modelo introductorio para quienes deseen tomar contacto con LINQ to Entities.
En ese artículo me salté (a propósito) muchos aspectos más introductorios si cabe sobre LINQ to Entities que me hubiera gustado abordar más adelante, pero que no voy a hacer ya que Juan Carlos González (CIIN) se me ha adelantado con una excelente entrada que aclara todas las cosas de las que quería hablar.
El caso es que al final de la primera entrada que escribí acerca de LINQ to Entities os comentaba lo siguiente:
«Ahora bien, si observamos con atención esta pantalla y el código escrito, y en concreto la instrucción Select p.Id, p.Nombre, p.Sexo, p.FechaNacimiento, CodigoPaisNacimiento = p.Pais.Codigo, CodigoClub = p.Club.Codigo, p.Posicion, veremos que el orden de los campos mostrados en el DataGridView no es el que esperábamos, o al menos no el que nos gustaría obtener. Además tenemos también una claúsula OrderBy que indicaría teóricamente un orden. ¿Porqué se da este comportamiento?.«
Y de eso os voy a hablar aquí. De esa «extraña» ordenación, del comando Select y del comando OrderBy.
¿Que es lo que ocurre para que el comportamiento del volcado de datos no sea es comportamiento esperado?.
Repasando el ejemplo que os propuse, en él se ejecutaba una sentencia LINQ completa (a continuación os pongo parte de la misma):
… Select p.Id, p.Nombre, p.Sexo, p.FechaNacimiento, CodigoPaisNacimiento = p.Pais.Codigo, _ CodigoClub = p.Club.Codigo, p.Posicion _ … |
Ante esto nos podemos poner a investigar algo que nuestra razón llegue a comprender y por eso, una forma de ver lo que ocurre es investigando, así que con VS 2008 como herramienta (no hace falta usar Reflector for .NET, pero si alguno quiere lo puede hacer y extraerá las mismas conclusiones…), observamos con el Watch de VS 2008 que los resultados que obtenemos nos muestra esos datos de forma ordenada según la instrucción Select.
Es decir, el método ToString() nos muestra los datos ordenadamente de acuerdo al Select de LINQ, de hecho, basta con ejecutar el siguiente comando para observar que los datos mostrados para una determinada lista aparecen ordenados según esa sentencia Select:
datos.ToList().Item(0).ToString()
Investigando un poco más del porqué de esta situación, vemos que en el Watch los datos aparecen ordenados alfabéticamente:
La primera pregunta por lo tanto es porqué ordena alfabéticamente .NET los datos.
En sí, cada dato corresponde con una propiedad y el hecho de que aparezcan ordenados no representa ninguna anomalía. Por lo tanto, el hecho de que aparezcan ordenados no es un problema (descartamos esto por lo tanto).
Después de ver este funcionamiento en VB 2008, la siguiente pregunta que nos hacemos o que nos podemos hacer es: ¿funcionará de la misma manera en C# 3.0?.
Si hacemos el mismo ejemplo de la anterior entrada pero para C#, veremos con el Watch que el método ToString() nos devuelve los datos igual que VB 2008, y que las propiedades de los elementos de cada resultado aparece ordenada alfabéticamente. Todo esto igual que en VB 2008.
Sin embargo, a la hora de mostrar los datos en el DataGridView, los datos aparecen en el mismo orden que la Select de LINQ.
Entonces,… ¿porqué en VB 2008 aparecen los datos mostrados anómalamente en el DataGridView y en C# 3.0 aparecen bien?.
Una vez más, podemos llegar a pensar en que OrderBy puede tener (a lo mejor) la culpa, así que si ponemos OrderBy tal y como está en el ejemplo original:
Dim datos = From p In contexto.Futbolista _ Where p.Club.Codigo = Me.codeClub _ Select p.Id, p.Nombre, p.Sexo, p.FechaNacimiento, CodigoPaisNacimiento = p.Pais.Codigo, _ CodigoClub = p.Club.Codigo, p.Posicion _ OrderBy Id, Nombre, Sexo, FechaNacimiento, CodigoPaisNacimiento, CodigoClub, p.Posicion |
Observaremos que da igual, los resultados del DataGridView en VB 2008 siguen saliendo mal ordenados de acuerdo a la Select de LINQ.
El caso es que OrderBy ordena los elementos por filas, no por columnas, pero Select sí ordena los datos por columnas, por lo que la explicación final es que VB 2008 y LINQ to Entities, extrae y vuelca mal los datos hacia el DataGridView.
¿Es un bug?.
En mi opinión es un mal funcionamiento y sí, puede calificarse como un bug.
¿Se resolverá el bug?.
Este mal funcionamiento ya lo he reportado a Microsoft (no sé si alguien lo habrá reportado antes) y sé que el equipo de LINQ to Entities está ya trabajando con este tema.
Recordemos que LINQ to Entities está aún en fase Beta 3 y no está en versión RTM definitiva.
¿Qué forma tenemos de resolver este problema?.
Existen varias, pero la «menos sucia» es mapear los elementos al DataGridView de forma que aparezcan ordenados.
La parte del ejemplo de la entrada inicial que hiciese las cosas como queríamos desde un principio quedaría de la siguiente forma:
Imports LINQtoEntities.Futbol2006Model Public Class MainForm … Private Sub btnSelectPlayers_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnSelectPlayers.Click ‘ Recuperamos la información que queremos buscar Dim codeClub As String = Me.cboClubs.SelectedValue.ToString() ‘ Obtenemos los datos de Futbolistas segel equipo seleccionado Dim datos = From p In contexto.Futbolista _ Where p.Club.Codigo = Me.codeClub _ Select p.Id, p.Nombre, p.Sexo, p.FechaNacimiento, CodigoPaisNacimiento = p.Pais.Codigo, _ CodigoClub = p.Club.Codigo, p.Posicion _ OrderBy Id, Nombre, Sexo, FechaNacimiento, CodigoPaisNacimiento, CodigoClub, p.Posicion ‘ Volcamos los datos en el DataGridView Me.dgvPlayers.DataSource = datos ‘ Mapeamos los resultados para mostrarlos adecuadamente en el control DataGridView Me.dgvPlayers.Columns(0).DataPropertyName = «Id» Me.dgvPlayers.Columns(0).HeaderText = «Id» Me.dgvPlayers.Columns(1).DataPropertyName = «Nombre» Me.dgvPlayers.Columns(1).HeaderText = «Nombre» Me.dgvPlayers.Columns(2).DataPropertyName = «Sexo» Me.dgvPlayers.Columns(2).HeaderText = «Sexo» Me.dgvPlayers.Columns(3).DataPropertyName = «FechaNacimiento» Me.dgvPlayers.Columns(3).HeaderText = «FechaNacimiento» Me.dgvPlayers.Columns(4).DataPropertyName = «CodigoPaisNacimiento» Me.dgvPlayers.Columns(4).HeaderText = «CodigoPaisNacimiento» Me.dgvPlayers.Columns(5).DataPropertyName = «CodigoClub» Me.dgvPlayers.Columns(5).HeaderText = «CodigoClub» Me.dgvPlayers.Columns(6).DataPropertyName = «Posicion» Me.dgvPlayers.Columns(6).HeaderText = «Posicion» ‘ Ajustamos los datos al control Me.dgvPlayers.AutoResizeColumns(DataGridViewAutoSizeColumnsMode.AllCells) End Sub … End Class |
De esta manera, aparecerán los datos correctamente mapeados.
A mí me parece una guarrada (con perdón), pero de momento no hay otra forma más elegante a la espera de que se resuelva este pequeño problema.
Espero que contando esto por aquí, le pueda servir de ayuda a más de uno si se encuentra con este extraño funcionamiento en VB 2008, y que lo tengamos resuelto en la versión definitiva de ADO.NET Entity Framework (pedir es gratis ¿verdad?).
4 Responsesso far
Hola Jorge!
Muy bueno el descubrimiento de esta anomalía, la verdad es que ni me había dado cuenta de este tema cuando he leido tu post…por otro lado, una vez más, excelente post!
JC’s
Hola Jorge.
A mi me ocurre esto mismo pero cuando utilizo una clase como origen de datos (las propiedades de la clase), se que no es lo mismo pero el resultado es igual no aparecen las columnas ordenadas en funcíon del oden de declaración de las propiedades.
Salu2
Introducción En las entradas anteriores que he tratado sobre LINQ, hemos visto inicialmente ( Parte 1
Excelentes ejemplos