none
Problema con LINQ to Dataset (Error de conversión de tipos) RRS feed

  • Pregunta

  • Hola a todos. Espero que estén bien. Estoy trabajando con LINQ to Dataset, tal como dice en el título. Se puede decir que esta pregunta es continuación de otra, pero que ya está resuelta, por lo que quizás no atraiga la atención. Esa pregunta está en el link http://social.msdn.microsoft.com/Forums/es-ES/vbes/thread/274d190b-5258-4a92-8f0d-67b8ddeb5728.

    Mi problema es el siguiente:
    Se me produce un error de conversión de tipos al ejecutar una consulta LINQ, cuando en la sentencia SELECT incluyo más de un dataRow (los cuales están enlazados mediante un JOIN) esta es la consulta que me produce error:

            'Creo la consulta LINQ 
    'AQUI SE PRODUCE EL ERROR DE CONVERSIÓN DE TIPOS
    Dim query As IEnumerable(Of DataRow) = From rowPersonas In dtPersonas.AsEnumerable _
    Join rowPagos In dtPagos.AsEnumerable _
    On rowPersonas.Field(Of Integer)("dni") Equals rowPagos.Field(Of Integer)("dni") _
    Order By rowPersonas.Field(Of String)("apeNom") _
    Select qryDNI = rowPersonas.Field(Of Integer)("dni"), _
    qryApeNom = rowPersonas.Field(Of String)("apeNom"), _
    qryLugarDesempeño = rowPersonas.Field(Of String)("lugar"), _
    qryCargo = rowPersonas.Field(Of String)("cargo"), _
    qryAPagar = rowPagos.Field(Of Double)("aPagar"), _
    qryPagado = rowPagos.Field(Of Double)("pagado")
    El error que se produce es el siguiente:

    No se puede convertir un objeto de tipo
    '<SelectIterator>d__d`2[VB$AnonymousType_0`2[System.Data.DataRow,System.Data.DataRow],VB$AnonymousType_1`6[System.Int32,System.String,System.String,System.String,System.Double,System.Double]]'
    al tipo 'System.Collections.Generic.IEnumerable`1[System.Data.DataRow]'.


    Sin embargo, cuando utilizo un query de tipo anónimo la consulta se ejecuta perfectamente. Yo necesito que sea del tipo IEnumerable(Of datarow), ya que debo utilizar el método query.CopyToDataTable que sólo está disponible para el tipo IEnumerable(Of datarow). En este caso no se produce el error (con tipo anónimo):

            'Creo la consulta LINQ 
    Dim query = From rowPersonas In dtPersonas.AsEnumerable _
    Join rowPagos In dtPagos.AsEnumerable _
    On rowPersonas.Field(Of Integer)("dni") Equals rowPagos.Field(Of Integer)("dni") _
    Order By rowPersonas.Field(Of String)("apeNom") _
    Select qryDNI = rowPersonas.Field(Of Integer)("dni"), _
    qryApeNom = rowPersonas.Field(Of String)("apeNom"), _
    qryLugarDesempeño = rowPersonas.Field(Of String)("lugar"), _
    qryCargo = rowPersonas.Field(Of String)("cargo"), _
    qryAPagar = rowPagos.Field(Of Double)("aPagar"), _
    qryPagado = rowPagos.Field(Of Double)("pagado")


    Espero que me puedan ayudar. Hace bastente que vengo renegando con esto. Le agradezco a SoftJaén que me ha ayudado bastante en el tema, pero aúnno consigo darle en la tecla.

    Saludos a todos. Leonardo González
    sábado, 29 de agosto de 2009 18:42

Respuestas

  • hola

    Estuve realizando pruebas aver si podia adaptar lo que intentas hacer, pero no llegue a buenos resultados

    Lo que haces al usar el Select es crear un objeto nuevo con las propiedades que determinas en el mismo select, esto hace que ha dejes de usar un objeto del tipo DataRow, por lo que la conversion no puede hacerla

    Por alguna razon necesitas si o si un IEnumerable(Of DataRow), digo no puedes crear una List(Of ...)
    o sea de algun tipo custom, pienso que castear a a una clase sera mas simple

    un ejemplo podrias sera de esta forma:



    Imports System.Data


    Public Class Form2


        Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click

            Dim dtPersonas As DataTable = cargarPersonas()
            Dim dtPagos As DataTable = cargarPagos()




            Dim query As IEnumerable(Of QueryResult) = (From rowPersonas In dtPersonas.AsEnumerable _
                        Join rowPagos In dtPagos.AsEnumerable _
                        On Convert.ToInt32(rowPersonas("dni")) Equals Convert.ToInt32(rowPagos("dni")) _
                        Order By rowPersonas.Field(Of String)("apeNom") _
                        Select New QueryResult With { _
                                .qryDNI = rowPersonas("dni").ToString, _
                                .qryApeNom = rowPersonas("apeNom").ToString, _
                                .qryLugarDesempeño = rowPersonas("lugar").ToString, _
                                .qryCargo = rowPersonas("cargo").ToString, _
                                .qryAPagar = rowPagos("aPagar").ToString, _
                                .qryPagado = rowPagos("pagado").ToString})


            If query.Count() > 0 Then

                For Each Item As QueryResult In query

                    Dim valores As String = String.Format("{0}, {1}, {2}", Item.qryDNI, Item.qryApeNom, Item.qryPagado)

                Next

            End If

        End Sub


     
        Private Function cargarPersonas() As DataTable

            Dim dtTemp As DataTable = New DataTable

            dtTemp.Columns.Add("dni")
            dtTemp.Columns.Add("apeNom")
            dtTemp.Columns.Add("lugar")
            dtTemp.Columns.Add("cargo")


            Dim dato1 As DataRow = dtTemp.NewRow
            dato1("dni") = "12345"
            dato1("apeNom") = "apellido1"
            dato1("lugar") = "lugar1"
            dato1("lugar") = "cargo1"

            Dim dato2 As DataRow = dtTemp.NewRow
            dato2("dni") = "3333"
            dato2("apeNom") = "apellido2"
            dato2("lugar") = "lugar2"
            dato2("lugar") = "cargo2"

            dtTemp.Rows.Add(dato1)

            Return dtTemp


        End Function

        Private Function cargarPagos() As DataTable

            Dim dtTemp As DataTable = New DataTable

            dtTemp.Columns.Add("dni")
            dtTemp.Columns.Add("aPagar")
            dtTemp.Columns.Add("pagado")


            Dim dato1 As DataRow = dtTemp.NewRow
            dato1("dni") = "12345"
            dato1("aPagar") = "120"
            dato1("pagado") = "1"

            dtTemp.Rows.Add(dato1)

            Return dtTemp


        End Function


        Private Class QueryResult

            Private _qryDNI As String

            Public Property qryDNI() As String
                Get
                    Return _qryDNI
                End Get
                Set(ByVal value As String)
                    _qryDNI = value
                End Set
            End Property


            Private _qryApeNom As String

            Public Property qryApeNom() As String
                Get
                    Return _qryApeNom
                End Get
                Set(ByVal value As String)
                    _qryApeNom = value
                End Set
            End Property

            Private _qryLugarDesempeño As String

            Public Property qryLugarDesempeño() As String
                Get
                    Return _qryLugarDesempeño
                End Get
                Set(ByVal value As String)
                    _qryLugarDesempeño = value
                End Set
            End Property

            Private _qryCargo As String

            Public Property qryCargo() As String
                Get
                    Return _qryCargo
                End Get
                Set(ByVal value As String)
                    _qryCargo = value
                End Set
            End Property

            Private _qryAPagar As Double

            Public Property qryAPagar() As Double
                Get
                    Return _qryAPagar
                End Get
                Set(ByVal value As Double)
                    _qryAPagar = value
                End Set
            End Property

            Private _qryPagado As Double

            Public Property qryPagado() As Double
                Get
                    Return _qryPagado
                End Get
                Set(ByVal value As Double)
                    _qryPagado = value
                End Set
            End Property

        End Class

    End Class




    Este es el formulario que use de ejemplo, si lo pegar a uno de ejemplo deberia poder ejecutarlo

    Veras como cree la clase QueryResult, que usare en reemplazo del DataRow, de esta forma si funciona

    El team con el datarow es que depende del datatable, y es por medio del metodo NewRow() del DataTable que creas nuevas rows, esto creo que influye al quere utilziarlo con nuevos registros, puede que me equivoque pero por ahi por ese lado viene el tema


    saludos
    Leandro Tuttini

    Blog
    Buenos Aires
    Argentina
    • Marcado como respuesta Leo González miércoles, 2 de septiembre de 2009 3:45
    sábado, 29 de agosto de 2009 21:52

Todas las respuestas

  • hola

    Estuve realizando pruebas aver si podia adaptar lo que intentas hacer, pero no llegue a buenos resultados

    Lo que haces al usar el Select es crear un objeto nuevo con las propiedades que determinas en el mismo select, esto hace que ha dejes de usar un objeto del tipo DataRow, por lo que la conversion no puede hacerla

    Por alguna razon necesitas si o si un IEnumerable(Of DataRow), digo no puedes crear una List(Of ...)
    o sea de algun tipo custom, pienso que castear a a una clase sera mas simple

    un ejemplo podrias sera de esta forma:



    Imports System.Data


    Public Class Form2


        Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click

            Dim dtPersonas As DataTable = cargarPersonas()
            Dim dtPagos As DataTable = cargarPagos()




            Dim query As IEnumerable(Of QueryResult) = (From rowPersonas In dtPersonas.AsEnumerable _
                        Join rowPagos In dtPagos.AsEnumerable _
                        On Convert.ToInt32(rowPersonas("dni")) Equals Convert.ToInt32(rowPagos("dni")) _
                        Order By rowPersonas.Field(Of String)("apeNom") _
                        Select New QueryResult With { _
                                .qryDNI = rowPersonas("dni").ToString, _
                                .qryApeNom = rowPersonas("apeNom").ToString, _
                                .qryLugarDesempeño = rowPersonas("lugar").ToString, _
                                .qryCargo = rowPersonas("cargo").ToString, _
                                .qryAPagar = rowPagos("aPagar").ToString, _
                                .qryPagado = rowPagos("pagado").ToString})


            If query.Count() > 0 Then

                For Each Item As QueryResult In query

                    Dim valores As String = String.Format("{0}, {1}, {2}", Item.qryDNI, Item.qryApeNom, Item.qryPagado)

                Next

            End If

        End Sub


     
        Private Function cargarPersonas() As DataTable

            Dim dtTemp As DataTable = New DataTable

            dtTemp.Columns.Add("dni")
            dtTemp.Columns.Add("apeNom")
            dtTemp.Columns.Add("lugar")
            dtTemp.Columns.Add("cargo")


            Dim dato1 As DataRow = dtTemp.NewRow
            dato1("dni") = "12345"
            dato1("apeNom") = "apellido1"
            dato1("lugar") = "lugar1"
            dato1("lugar") = "cargo1"

            Dim dato2 As DataRow = dtTemp.NewRow
            dato2("dni") = "3333"
            dato2("apeNom") = "apellido2"
            dato2("lugar") = "lugar2"
            dato2("lugar") = "cargo2"

            dtTemp.Rows.Add(dato1)

            Return dtTemp


        End Function

        Private Function cargarPagos() As DataTable

            Dim dtTemp As DataTable = New DataTable

            dtTemp.Columns.Add("dni")
            dtTemp.Columns.Add("aPagar")
            dtTemp.Columns.Add("pagado")


            Dim dato1 As DataRow = dtTemp.NewRow
            dato1("dni") = "12345"
            dato1("aPagar") = "120"
            dato1("pagado") = "1"

            dtTemp.Rows.Add(dato1)

            Return dtTemp


        End Function


        Private Class QueryResult

            Private _qryDNI As String

            Public Property qryDNI() As String
                Get
                    Return _qryDNI
                End Get
                Set(ByVal value As String)
                    _qryDNI = value
                End Set
            End Property


            Private _qryApeNom As String

            Public Property qryApeNom() As String
                Get
                    Return _qryApeNom
                End Get
                Set(ByVal value As String)
                    _qryApeNom = value
                End Set
            End Property

            Private _qryLugarDesempeño As String

            Public Property qryLugarDesempeño() As String
                Get
                    Return _qryLugarDesempeño
                End Get
                Set(ByVal value As String)
                    _qryLugarDesempeño = value
                End Set
            End Property

            Private _qryCargo As String

            Public Property qryCargo() As String
                Get
                    Return _qryCargo
                End Get
                Set(ByVal value As String)
                    _qryCargo = value
                End Set
            End Property

            Private _qryAPagar As Double

            Public Property qryAPagar() As Double
                Get
                    Return _qryAPagar
                End Get
                Set(ByVal value As Double)
                    _qryAPagar = value
                End Set
            End Property

            Private _qryPagado As Double

            Public Property qryPagado() As Double
                Get
                    Return _qryPagado
                End Get
                Set(ByVal value As Double)
                    _qryPagado = value
                End Set
            End Property

        End Class

    End Class




    Este es el formulario que use de ejemplo, si lo pegar a uno de ejemplo deberia poder ejecutarlo

    Veras como cree la clase QueryResult, que usare en reemplazo del DataRow, de esta forma si funciona

    El team con el datarow es que depende del datatable, y es por medio del metodo NewRow() del DataTable que creas nuevas rows, esto creo que influye al quere utilziarlo con nuevos registros, puede que me equivoque pero por ahi por ese lado viene el tema


    saludos
    Leandro Tuttini

    Blog
    Buenos Aires
    Argentina
    • Marcado como respuesta Leo González miércoles, 2 de septiembre de 2009 3:45
    sábado, 29 de agosto de 2009 21:52
  • "Leo González" escribió:

    > Sin embargo, cuando utilizo un query de tipo anónimo la consulta se ejecuta perfectamente.
    > Yo necesito que sea del tipo IEnumerable(Of datarow), ya que debo utilizar el método
    > query.CopyToDataTable que sólo está disponible para el tipo IEnumerable(Of datarow).

    Leo, ya te he comentado varias veces, QUE NO SE PUEDE CONVERTIR UN TIPO ANÓNIMO EN UN OBJETO IEnumerable(Of DataRow). Es como si deseas convertir un objeto del tipo Image en un valor Integer, por poner un ejemplo un tanto descabellado de conversión de datos.

    En la otra conversación que tienes abeirta, ya te he dicho que crees un objeto DataTable como resultado de ejecutar una consulta de selección INNER JOIN directamente a la base de datos.


    Enrique Martínez [MS MVP - VB]
    domingo, 30 de agosto de 2009 9:12
    Moderador
  • "Leandro Tuttini" escribió:

    > Estuve realizando pruebas aver si podia adaptar lo que intentas hacer, pero no llegue a buenos resultados

    Y no vas a llegar a buenos resultados, porque lo que desea el usuario Leo González es tener un objeto DataTable como resultado de ejecutar la consulta LINQ de combinación (JOIN) utilizando tipos anónimos, y eso, ya sabes, que no se puede obtener, o al menos, yo ignoro cómo se puede obtener directamente.

    Si utiliza tipos anónimos, lo único factible que veo es crear directamente la estructura del objeto DataTable, y posteriormente añadir los registros conforme se van recorriendo los elementos del objeto List(T) resultante de la llamada al método ToList() del tipo anónimo declarado.

    Creo que el siguiente ejemplo muestra lo que quiero decir:


            Dim dtClientes As DataTable = New DataTable("Clientes")
            Dim dtFacturas As DataTable = New DataTable("Facturas")
    
            ' Rellenamos los objetos DataTable
            '
            Using cnn As New SqlConnection("Data Source=(local);" & _
                                           "Initial Catalog=Prueba;" & _
                                           "Integrated Security=SSPI")
    
                Dim sql As String = "SELECT * FROM Clientes"
    
                Dim da As New SqlDataAdapter(sql, cnn)
    
                da.Fill(dtClientes)
    
                sql = "SELECT * FROM Facturas"
    
                da = New SqlDataAdapter(sql, cnn)
    
                da.Fill(dtFacturas)
    
            End Using
    
            ' Ejecutamos la consulta LINQ combinada
            '
            Dim query = _
                   From rowClientes In dtClientes _
                   Join rowFacturas As DataRow In dtFacturas _
                   On rowClientes.Field(Of Int32)("IdCliente") Equals rowFacturas.Field(Of Int32)("IdCliente") _
                   Where rowClientes.Field(Of Int32)("IdCliente") = 4300018 _
                   Order By rowFacturas.Field(Of Int32)("IdFactura") _
                   Select New With { _
                       .IdFactura = rowFacturas.Field(Of Int32)("IdFactura"), _
                       .Nombre = rowClientes.Field(Of String)("Nombre"), _
                       .Total = rowFacturas.Field(Of Single)("Total") _
                   }
    
            ' Creamos la estructura del objeto DataTable combinado.
            '
            Dim dtCombinada As DataTable = New DataTable("TablaCombinada")
    
            Dim dc As DataColumn = New DataColumn("IdFactura", GetType(Int32))
            dtCombinada.Columns.Add(dc)
    
            dc = New DataColumn("Nombre", GetType(String))
            dtCombinada.Columns.Add(dc)
    
            dc = New DataColumn("Total", GetType(Single))
            dtCombinada.Columns.Add(dc)
    
            ' Añadimos los registros al objeto DataTable
            '
            For Each row In query.ToList
                Dim values() As Object = {row.IdFactura, row.Nombre, row.Total}
                dtCombinada.LoadDataRow(values, True)
            Next
    
            ' Enlazamos el objeto DataTable combinado con el
            ' control DataGridView.
            '
            DataGridView1.DataSource = dtCombinada
    


    Por ahora no se me ocurre otra cosa para poder tener disponible un objeto DataTable como resultado de ejecutar una consulta LINQ que utiliza tipos anónimos.




    Enrique Martínez [MS MVP - VB]
    domingo, 30 de agosto de 2009 9:38
    Moderador
  • Es que quizás el problema sea: No puede ejecutar directamente desde la Base de Datos porque necesita traer datos de dos o más bases de datos... Bah, yo me identifico con esto, jaja.
    Gabriela
    lunes, 31 de agosto de 2009 0:22
  • Gabriela, el problema de Leo es el mismo que tenías tú con cierta consulta LINQ.


    Enrique Martínez [MS MVP - VB]
    martes, 1 de septiembre de 2009 13:50
    Moderador