none
crystal reports con dos datatables en un dataset RRS feed

  • Pregunta

  • Buenos días,

    se que se ha escito sobre esto antes, pero no soy capaz de hacer que funcione mi código. En otro post alguien puso un enlace para solucionar esta cuestión a esta página: http://ltuttini.blogspot.com.es/2009/12/c-crystal-reports-usar-dataset-tipado.html sin embargo a mi no me funciona. Pego el código a ver si alguien me puede ayudar:

       Private Sub Parametros_Crystal()
            Dim oCnn As New OleDbConnection        ' Objeto de conexion a la base de datos
            Dim da_Datos As New OleDbDataAdapter   ' Objeto Adaptador para leer datos de la Base de datos
    
            Dim dt_Eventos As New DataTable        ' Datatable para recibir los datos de la base de datos
            Dim cmdExec1 As New OleDbCommand       ' Objeto comando para ejecutar sentencias sql
            Dim sbQuery1 As New StringBuilder      ' StringBuilder para armar cadenas
    
            Dim dt_Personal As New DataTable        ' Datatable para recibir los datos de la base de datos
            Dim cmdExec2 As New OleDbCommand       ' Objeto comando para ejecutar sentencias sql
            Dim sbQuery2 As New StringBuilder      ' StringBuilder para armar cadenas
    
    
    
            Try
                oCnn.ConnectionString = "Provider=Microsoft.Jet.OLEDB.4.0; Data Source=" & Ruta_Fichero
                oCnn.Open()
                
    
    
                ' EVENTOS ***************
                cmdExec1 = oCnn.CreateCommand
                cmdExec1.Connection = oCnn
    
                sbQuery1.Append("SELECT ID_Evento  ")
                sbQuery1.Append("      ,Fecha  ")
                sbQuery1.Append("      ,Dia_Semana  ")
                sbQuery1.Append("      ,ID_Empleado  ")
                sbQuery1.Append("      ,Hora_Inicio  ")
                sbQuery1.Append("      ,Hora_Fin  ")
                sbQuery1.Append("      ,Tipo_Evento  ")
                sbQuery1.Append("      ,Horas  ")
                sbQuery1.Append("      ,Minutos  ")
                sbQuery1.Append("      ,Total_Minutos  ")
                sbQuery1.Append("      ,Error  ")
                sbQuery1.Append("            FROM Eventos   ")
    
                cmdExec1.CommandText = sbQuery1.ToString
    
                da_Datos = New OleDbDataAdapter(cmdExec1)
                'da_Datos.Fill(dt_Eventos)
                da_Datos.Fill(dt_Eventos, "Eventos") ' versión Tuttini
    
    
                ' PERSONAL ***************
                cmdExec2 = oCnn.CreateCommand
                cmdExec2.Connection = oCnn
    
                sbQuery2.Append("SELECT ID_Empleado  ")
                sbQuery2.Append("      ,Nombre  ")
                sbQuery2.Append("      ,Apellidos  ")
                sbQuery2.Append("      ,Horas_Jornada  ")
                sbQuery2.Append("      ,Minutos_Jornada  ")
                sbQuery2.Append("            FROM Personal   ")
    
                cmdExec2.CommandText = sbQuery2.ToString
    
                da_Datos = New OleDbDataAdapter(cmdExec2)
                'da_Datos.Fill(dt_Personal)
                da_Datos.Fill(dt_Eventos, "Personal") ' Versión Tuttini
    
    
    
    
    
    
                Dim CrReport As New CrystalDecisions.CrystalReports.Engine.ReportDocument
                ' Asigno el reporte
                CrReport = New CrystalDecisions.CrystalReports.Engine.ReportDocument()
    
    
    
                
                Ruta_Reporte = Ruta_Reporte & "\cr_Informe.rpt"
    
    
    
                CrReport.Load(Ruta_Reporte)
                CrReport.SetDataSource(dt_Eventos)
                'CrReport.SetDataSource(dt_Personal)
    
                crv_Informe.ReportSource = CrReport
    
    
            Catch ex As Exception
                MessageBox.Show(ex.ToString, "Mostrando Informe")
            End Try
    
        End Sub

    Si ejecuto el código en la "versión Tuttini" me da el error "El objeto no es ADODB.Record. nombre del parámetro: adodb". Y si lo ejecuto tal y como está, solo puedo pasarle un datatable al dataset.



    Espero que alguien me pueda ayudar, muchas gracias de antemano.


    • Editado davidsap martes, 26 de agosto de 2014 10:23
    martes, 26 de agosto de 2014 10:21

Todas las respuestas

  • Hola:
    ¿No puedes hacer una consulta que implique a todos los campos que necesita el informe aunque sean de diferentes tablas?
    Prueba a poner las estructuras de las tablas y los campos que quieres que salgan en el informe, a ver si se encuentra alguan solucion.

    Un saludo desde Bilbo
    Carlos

    martes, 26 de agosto de 2014 10:32
  • Hola:
    ¿No puedes hacer una consulta que implique a todos los campos que necesita el informe aunque sean de diferentes tablas?
    Prueba a poner las estructuras de las tablas y los campos que quieres que salgan en el informe, a ver si se encuentra alguan solucion.

    Un saludo desde Bilbo
    Carlos

    Buenos días Carlos,

    esa era mi segunda opción, hacer una consulta con inner join y coger directamente todos los datos en una tabla. Lo que pasa es que lo veo menos "profesional", si hay 5 personas con 1000 eventos una, estoy repitiendo innecesariamente columnas en 4995 registros. Aunque desde luego si no me queda otra es lo que haré.

    A ver si alguien me puede decir cómo pasar los dos datatables. En cualquier caso, muchas gracias por tu respuesta.

    Un saludo,

    David

    miércoles, 27 de agosto de 2014 8:46
  • hola

    unos comentarios, si usas el CreateCommand desde el objeto de conexion no necesitas en la siguiente linea volver asignar la conexion

    tambien aqui Dim CrReport As New CrystalDecisions.CrystalReports.Engine.ReportDocument si ya has puesto el new no necesitas crear la instnacia nuevamente

    ----

    el error que mencionas puedes detectar en que linea se produce ? es cuando haces el Fill() o cuando asignas a crystal el dataset

    saludos


    Leandro Tuttini

    Blog
    MVP Profile
    Buenos Aires
    Argentina

    miércoles, 27 de agosto de 2014 16:19
  • hola

    unos comentarios, si usas el CreateCommand desde el objeto de conexion no necesitas en la siguiente linea volver asignar la conexion

    tambien aqui Dim CrReport As New CrystalDecisions.CrystalReports.Engine.ReportDocument si ya has puesto el new no necesitas crear la instnacia nuevamente

    ----

    el error que mencionas puedes detectar en que linea se produce ? es cuando haces el Fill() o cuando asignas a crystal el dataset

    saludos


    Leandro Tuttini


    Muchas gracias por tu respuesta,

    he corregido ese par de cosas que comentas. LA verdad es que el código lo había copiado de una página por ahí en Internet.

    En cuanto al error me sale en la línea:

    da_Datos = New OleDbDataAdapter(cmdExec1)

    miércoles, 27 de agosto de 2014 16:42
  • hola

    creo que ya se cual es el problema

    OleDbDataAdapter.Fill (Método) (DataTable, Object)

    el segundo parametro no puede ser un string, tienes que ser un adodb recordset, por eso cuando haces

    da_Datos.Fill(dt_Eventos, "Eventos")

    falla, porque deberias usar

    da_Datos.Fill(dt_Eventos)

    el segundo parametro no lo deberias asignar

    saludos


    Leandro Tuttini

    Blog
    MVP Profile
    Buenos Aires
    Argentina

    miércoles, 27 de agosto de 2014 16:50
  • Hola:
     "si hay 5 personas con 1000 eventos una, estoy repitiendo innecesariamente columnas en 4995 registros"

    Si solo quieres mostrar 5 registros, no tienes que implicar a la tabla eventos.
    Si quieres mostrar algun campo de la tabla eventos, tienes que mostrar los 5000 registros

    El origen de datos para un fichero "RPT" tiene que ser un datatable ó algo similar, no veo como puedes pasar 2 datatables.
    ¿No puedes hacer una consulta que implique a todos los campos que necesita el informe aunque sean de diferentes tablas?

    Un saludo desde Bilbo
    Carlos

    jueves, 28 de agosto de 2014 7:09
  • hola

    creo que ya se cual es el problema


    el segundo parametro no puede ser un string, tienes que ser un adodb recordset, por eso cuando haces

    da_Datos.Fill(dt_Eventos, "Eventos")

    falla, porque deberias usar

    da_Datos.Fill(dt_Eventos)

    el segundo parametro no lo deberias asignar

    saludos


    Leandro Tuttini


    Buenos Aires
    Argentina

    Así es como lo tenía en un principio, pero no puedo pasarle los dos dataset, tengo que elegir entre uno y otro.

    Si hago solo el CrReport.SetDataSource(dt_Personal) me aparecen los datos de personal, y si hago solo el CrReport.SetDataSource(dt_Eventos) me aparecen correctamente los datos de los eventos, pero si hago los dos, me aparece el informe en blanco.

    A continuación te pego el código (aplicando el par de correcciones que indicabas, ahora se ve más claro):

    Private Sub Parametros_Crystal()
            Dim oCnn As New OleDbConnection        ' Objeto de conexion a la base de datos
            Dim da_Datos As New OleDbDataAdapter   ' Objeto Adaptador para leer datos de la Base de datos
    
            Dim dt_Eventos As New DataTable        ' Datatable para recibir los datos de la base de datos
            Dim cmdExec1 As New OleDbCommand       ' Objeto comando para ejecutar sentencias sql
            Dim sbQuery1 As New StringBuilder      ' StringBuilder para armar cadenas
    
            Dim dt_Personal As New DataTable        ' Datatable para recibir los datos de la base de datos
            Dim cmdExec2 As New OleDbCommand       ' Objeto comando para ejecutar sentencias sql
            Dim sbQuery2 As New StringBuilder      ' StringBuilder para armar cadenas
    
    
    
            Try
                oCnn.ConnectionString = "Provider=Microsoft.Jet.OLEDB.4.0; Data Source=" & Ruta_Fichero
                oCnn.Open()
    
    
    
                ' EVENTOS ***************
                cmdExec1 = oCnn.CreateCommand
    
                sbQuery1.Append("SELECT ID_Evento  ")
                sbQuery1.Append("      ,Fecha  ")
                sbQuery1.Append("      ,Dia_Semana  ")
                sbQuery1.Append("      ,ID_Empleado  ")
                sbQuery1.Append("      ,Hora_Inicio  ")
                sbQuery1.Append("      ,Hora_Fin  ")
                sbQuery1.Append("      ,Tipo_Evento  ")
                sbQuery1.Append("      ,Horas  ")
                sbQuery1.Append("      ,Minutos  ")
                sbQuery1.Append("      ,Total_Minutos  ")
                sbQuery1.Append("      ,Error  ")
                sbQuery1.Append("            FROM Eventos   ")
    
                cmdExec1.CommandText = sbQuery1.ToString
    
                da_Datos = New OleDbDataAdapter(cmdExec1)
                da_Datos.Fill(dt_Eventos)
    
    
    
    
                ' PERSONAL ***************
                cmdExec2 = oCnn.CreateCommand
    
                sbQuery2.Append("SELECT ID_Empleado  ")
                sbQuery2.Append("      ,Nombre  ")
                sbQuery2.Append("      ,Apellidos  ")
                sbQuery2.Append("      ,Horas_Jornada  ")
                sbQuery2.Append("      ,Minutos_Jornada  ")
                sbQuery2.Append("            FROM Personal   ")
    
                cmdExec2.CommandText = sbQuery2.ToString
    
                da_Datos = New OleDbDataAdapter(cmdExec2)
    
    
                da_Datos.Fill(dt_Personal)
    
    
    
    
    
                ' Elimina el bin\Debug si es necesario
                Dim Ruta_Reporte As String
                Ruta_Reporte = System.IO.Directory.GetCurrentDirectory.ToString
                If Microsoft.VisualBasic.Right(Ruta_Reporte, 9) = "bin\Debug" Then
                    Ruta_Reporte = Microsoft.VisualBasic.Left(Ruta_Reporte, Len(Ruta_Reporte) - 9)
                End If
                Ruta_Reporte = Ruta_Reporte & "\cr_Informe.rpt"
    
    
    
                ' Asigna los datos del reporte ************
                Dim CrReport As New CrystalDecisions.CrystalReports.Engine.ReportDocument
                CrReport.Load(Ruta_Reporte)
                'CrReport.SetDataSource(dt_Eventos)  'Si descomento esta línea el informe aparece vaío
                CrReport.SetDataSource(dt_Personal)
    
                crv_Informe.ReportSource = CrReport
    
    
            Catch ex As Exception
                MessageBox.Show(ex.ToString, "Mostrando Informe")
            End Try
    
        End Sub




    • Editado davidsap jueves, 28 de agosto de 2014 14:47
    jueves, 28 de agosto de 2014 14:46
  • Hola:
     "si hay 5 personas con 1000 eventos una, estoy repitiendo innecesariamente columnas en 4995 registros"

    Si solo quieres mostrar 5 registros, no tienes que implicar a la tabla eventos.
    Si quieres mostrar algun campo de la tabla eventos, tienes que mostrar los 5000 registros

    El origen de datos para un fichero "RPT" tiene que ser un datatable ó algo similar, no veo como puedes pasar 2 datatables.
    ¿No puedes hacer una consulta que implique a todos los campos que necesita el informe aunque sean de diferentes tablas?

    Un saludo desde Bilbo
    Carlos

    Muchas gracias Carlos,

    Pues al final es lo que voy a hacer. Como trabajo con una BD temporal de access (porque los datos los cojo de MySQL), he creado una tabla con todos los campos y la relleno con un INNER JOIN.

    Lo malo como te decía, es que si hay 5 empleados con 1000 registros cada uno, en vez de aparecer en la tabla el número de empleado 5000 veces, aparece también 5000 veces el nombre, los apellidos, etc... Pero la verdad es que así me voy a quitar muchos problemas y es más sencillo. Además tampoco creo que se ralentice el informe en más de un segundo.

    martes, 2 de septiembre de 2014 8:31
  • Hola:
    "aparece también 5000 veces el nombre, los apellidos, etc"
    Si quieres suprimir los valores duplicados, haces click derecho sobre el campo que quieres evitar los duplicados > dar formato a objeto y veras la siguiente imagen


    Marcas el checkbox y consigues que no se muestren los duplicados
     
    Un saludo desde Bilbo
    Carlos

    viernes, 5 de septiembre de 2014 9:15