sábado, 12 de diciembre de 2009

[Crystal Reports] Usar DataSet Tipado con dos DataTable

 

Introducción 

La finalidad de este articulo es muy puntual e intentara demostrar como hacer uso en un reporte de Crystal un DataSet Tipado que contiene dos DataTable en su interior.

En este caso se necesita listar los contactos de una empresa, pero para ello no solo se debe contar con los datos de los contactos, sino que además se desea enviar en el mismo origen de datos la información de la empresa.

Para esta operación es que se hace uso de un mismo DataSet Tipado, pero este contendrá dos tablas, las cuales serán cargadas de forma independiente, pero todo el conjunto será enviado como DataSource al reporte.

Para la operación se carga del dataset es que se ha creado un método que permite bajo la misma conexión cargar ambas tablas

public static dtoContactosEmpresa GetContactosEmpresa()
{
    dtoContactosEmpresa dtContactosEmpresa = new dtoContactosEmpresa();


    using (OleDbConnection conn = new OleDbConnection(ConfigurationManager.ConnectionStrings["default"].ToString()))
    {

        #region Cargo Datos Empresa

        string sql = @"SELECT IdEmpresa
                          ,RazonSocial
                          ,Telefono
                          ,Direccion
                          ,CUIT
                      FROM Empresas";

        OleDbCommand command = new OleDbCommand(sql, conn);

        OleDbDataAdapter da = new OleDbDataAdapter(command);

        da.Fill(dtContactosEmpresa, "DatosEmpresa");

        #endregion

        #region Cargo Contactos

        sql = @"SELECT Nombre
                  ,Apellido
                  ,FechaNacimiento
                  ,Localidad
                  ,Calle
                  ,Numero
                  ,Mail
              FROM Contacto";


        command = new OleDbCommand(sql, conn);

        da = new OleDbDataAdapter(command);

        da.Fill(dtContactosEmpresa, "Contactos");

        #endregion

    }

    return dtContactosEmpresa;
}

Es importante remarcar como al hacer el Fill() de los datos se especifica el nombre del datatable donde se quiere volcar la información (líneas 22 y 42)

 

[C#]
[VB.NET]

35 comentarios:

Chipujin dijo...

Hola leandro.
estoy creando un reporte con mas de dos tablas pero en formularios web y me estoy basando en en el ejemplo que publicaste, lo que no entiendo es por que el crystal report usando winform te crea un archivo cs y el crystal report usando webform no lo crea, y nose si sea por eso que al llamarlo en webform no me imprima ningun dato.
Por tu atencion gracias.
Saludos...

Chipujin dijo...

Hola Leandro.
Espero y me puedas ayudar, quiero cargar directamente un crystal report en formato pdf, pero el problema es que me marca un error que me dice "Faltan valores de parámetro".
el reporte lo cargo desde un procedimiento almacenado y utilizo un parametro en la consulta...
las linea de codigo que tengo para convertir es la sig:
reporte.ExportToHttpResponse(ExportFormatType.PortableDocFormat, Response, true, "MiReporte.rpt");
Saludos...

Leandro Tuttini dijo...

hola Chipujin

ReportDocument.ExportToHttpResponse Método

hasta donde puedo ver pareceria estar correcto, quizas el MiReporte.rpt, no deberias definirlo

algo que no ahs comentado es si este error se produce cuando compilas o en la jecucion cuando pasa por alli

saludos

Chipujin dijo...

Hola Leandro.
se produce en la ejecución cuando pasa por allí, y el error que me dice es que "faltan valores de parámetro".
El código completo que tengo es el siguiente:
string Folio = Session["Folio"].ToString();
ReportDocument reporte = new ReportDocument();
ParameterField pf = new ParameterField();
ParameterFields pfs = new ParameterFields();
ParameterDiscreteValue pdv = new ParameterDiscreteValue();

pf.Name = "@QuejaFolio";
pdv.Value = Folio;
pf.CurrentValues.Add(pdv);
pfs.Add(pf);
CRVReporteFolio.ParameterFieldInfo = pfs;
reporte.Load(Server.MapPath(@"CRReporteFolio.rpt"));
reporte.ExportToHttpResponse(ExportFormatType.PortableDocFormat, Response, false, "");
reporte.SetDatabaseLogon("Heri", "heri", @"HERIBERTO-HP\SQLEXPRESS", "ControlQuejas");
Saludos...

Cannibal dijo...

Oye Leandro como creaste ese Dataset tipado ? veo tu código pero no entiendo unas cosas como de donde salió el dtoContactosEmpresa.cs con un:
public partial class dtoContactosEmpresa {
partial class ContactosDataTable //<-- Este de donde salió ? tú lo creaste ?
{
}
}
Porque cuando yo mando instanciar el mio me marca un error. Además de que en mi dataset solo tengo esto:
public partial class dsTblComp {

}
Y cuando quiero hacer el
oda.Fill(ds, "MidataTableEnMiDataset"); Me marca el error:
"La mejor coinicidencia de método sobrecargado es System.Data.Common.DbDataAdapter.Fill" Tiene algunos argumentos no válidos.

Leandro Tuttini dijo...

hola Cannibal

respondi en el foro

http://social.msdn.microsoft.com/Forums/es-ES/vcses/thread/fbfa4189-0add-46ed-bbfb-d916132d183a

saludos

Cannibal dijo...

Oye Leandro como creaste ese Dataset tipado de tu ejemplo? Fue a través del asistente ? Veo tu código pero no entiendo unas cosas como de donde salió el dtoContactosEmpresa.cs

Además de que contiene la instancia pero además un ContactosDataTable que no sé de donde sale:
public partial class dtoContactosEmpresa {
partial class ContactosDataTable //<-- Este de donde salió ? tú lo creaste ?
{
}
}
Porque cuando yo mando instanciar el mio me marca un error. Además de que en mi dataset solo tengo esto:
public partial class dsTblComp {
}
Y cuando quiero hacer el
oda.Fill(ds, "MidataTableEnMiDataset"); Me marca el error:
"La mejor coinicidencia de método sobrecargado es System.Data.Common.DbDataAdapter.Fill" Tiene algunos argumentos no válidos.

Me puedes ayudar con esto ? Espero y ya terminar pronto.

Otra cosa...para usar dataset tipados necesito instalar el cliente de oracle -cosa que no uso- porque se me hace algo muy pesado y además al crear dataset de este tipo la aplicación se vuelve más lenta. Es por eso que no los uso. Tengo otra app donde agregué varios Dataset tipados y era una catástrofe de lentitud. Al menos con oracle. Hay manera de hacer esto que no sea con Datasets tipados ?

LEONARDO LIRA dijo...

hola leandro oye mira yo uso adodb en mi proyecto ya tengo diseñado mi crystal report lo malo es que no se como en lazar los campos con la tabla ya en lase el dataset y jale los campos al crystal reports pero no me apese ni un dato que sera

Leandro Tuttini dijo...

hola LEONARDO

una pregunta mas alla que uses oledb o algo diferente, has creado un dataset tipado ?

o sea tienes un .xsd que defina la estructura de tablas (por medio de datatable) y campos
porque es por medio de estos que enlazas con el reporte

saludos

Alfredo Adonis Amstrong dijo...

He visto tu post el cual me interesado bastante debido a que he creado una aplicacion en vb.net utilizando como base de datos Mysql y mi problema radica en la creacion de dataset que pueda utilizarlo en los reportes, los cuales no sea hecho por asistente, estoy utilizando como driver de coneccion hacia mysql .net y utilizare crystal reports. necesito de su ayuda, cualquier cosa escribirme a adonys28@gmail.com

Leandro Tuttini dijo...

hola Alfredo

puedes usar sin problemas mysql como origen de datos para cargar dataset tipados ya que cuantas con el conector de ado.net para mysql

analiza la respuesta que aqui brindo

http://social.msdn.microsoft.com/Forums/es-ES/netfxes/thread/f36fe79a-c4be-43a5-9743-a28cb16e6cab

si comparas el codigo que use para cargar los datatable del dataset en este articulo con las clases que se usa en el proveedor de mysql para mysql son practicamente identicas

saludos

Jimmy Ortiz dijo...

Sr. Leandro Por favor puede publicar ejemplos de crystal reports con subreportes, embebido , incrustado , es que tengo un problema , he hecho un reporte con 3 store procedure y solo m muestra uno los demas nada, apesar que los he vinculado.. se agradeceria bastante gracias

Jorge Luis Andres Murillo Soria dijo...

Leandro muchas gracias, siempre que puedo trato de encontrar tus ejemplos, son claras y simples de entender.

Victor dijo...

Me gustaría saber si hay crystal reports para visual studio 2012
Si alguien sabes porfa dejo mi correo vajm25@hotmail.com

Leandro Tuttini dijo...

hola victor

sabes que es todo un tema

hasta donde puede ver aun no hay soporte de Crystal para 2012

http://social.msdn.microsoft.com/Forums/es/vsrepcrystales/thread/257a2e35-7d59-4581-9c4c-a38387d615fc

quizas deberias analizar de usar Reporting Service

saludos

Norman dijo...

Hola Leandro

Tengo una consulta, estoy tratando de crear un reporte con procedimiento almacenado que recibe como parametro dos fechas. Según mi codigo lo cargo a un datatable de un data set. pero al momento de volcarlo al reporte en cristal report me carga en blanco el informe

Dime si esta es la mejor forma de acuerto a este codigo que te adjunto.


Sub con_parametros(parametro1 As String, parametro2 As String)

Dim myData As New DataSet1
Dim conn As New MySqlConnection("server=xx.xx.xx.xx;user=yyyy;password=zzzz;database=AAAA;port=3306")
Dim cmd As New MySqlCommand
Dim myAdapter As New MySqlDataAdapter
Dim myReport As New ReportDocument
Dim dt As New DataTable
dt.TableName = "p_rpt_ausencias"

Try
conn.Open()
'cmd.CommandText = "call p_rpt_ausencias @fInicio, @fFin "
cmd.CommandText = "call p_rpt_ausencias (" + parametro1 + ", " + parametro2 + " ) "
cmd.Connection = conn
myAdapter.SelectCommand = cmd

myAdapter.Fill(dt)
' Para crear el XML de datos
'myData.WriteXml("C:\dataset.xml", XmlWriteMode.WriteSchema)
myData.Tables(0).Merge(dt)
myReport.Load("C:\Users\Hans\Desktop\SGRRHH\SGRRHH\SGRRHHLL\SGRRHHLL\rpt_ausencias.rpt")
myReport.SetDataSource(myData)
myViewer.ReportSource = myReport
myViewer.Refresh()
Catch ex As Exception
MessageBox.Show(ex.Message, "El reporte no se pudo crear", MessageBoxButtons.OK, MessageBoxIcon.Error)
End Try

End Sub

Leandro Tuttini dijo...

hola

para invocar a un procesure no se usa el call, deebrias usar algo como ser

Dim dt As DataTabla = New DataTable()
Using conn As New SqlConnection("connectionstring")

Dim cmd As New SqlCommand("", conn)
cmd.CommandType = SqlCommandType.StoredProcedure

cmd.Parameters.AddWithValue("@param1", valor)

Dim da As New SqlDataAdapter(cmd)
da.Fill(dt)
End Using

es mas si usas un dataset para el reporte cargalo directo, usando

da.Fill(ds, "nombredatatable")

asi no tendras que ahcer ningun Merge()


saludos

Franky dijo...

Hola Leandro buenas noches, agradecere que me ayudes ,,tengo un procedimiento almacenado en un tableadapter de un dataset tipado,lo que quiero es pasarle 2 parametros texto para que me filtre en un reporte Crystal Report Viewer..gracias por la atencion

Leandro Tuttini dijo...

hola Franky

podrias extender la funcionalidad del tableadapter para incorporar los parametros

Building a DAL using Strongly Typed TableAdapters and DataTables in VS 2005 and ASP.NET 2.0

Tutorial 1: Creating a Data Access Layer

como veras en los articulo un tableadapter se puede agregar o modificar metodos para definir queries propias

saludos

Franky dijo...

Hola Leandro, gracias por tu apoyo con el enlace, alfin logre hacerlo, una consulta mas; porque el crystal reports no cargaba hasta que en el app.config le coloque useLegacyV2RuntimeActivationPolicy="true" en ...esa duda es la que tengo ahora o si es que me dara problemas mas adelante ya que e colocado como comentario la parte de sku=".NETFramework,Version=v4.0"...nuevamente muchas gracias.

Leandro Tuttini dijo...

hola Franky

la verdad es raro, sera que esos reportes los convertiste de un proyecto original en VS 2008 ? si es una conversion de un proyecto 2008 a 2010 puede que eso es lo que hace que necesite es opcion

sino la verdad no me explico que podra ser

saludos

Orlando Sanchez dijo...

Hola Leandro realice mi reporte y si me da resultado con el dataset pero tengo el problema que cuando abro el form el crystalviewer se tarda en ejecutar la primera ves ya la segunda es rapida eso pasa con cualquiera de mis reportes la primera ves, me podrias ayudar si es que tengo que agregar alguna linea de codigo al inicio para que no pase esto, desde ya te agradesco

Leandro Tuttini dijo...

hola Orlando

es que no se puede evitar, la primera vez siempre va a demorar mas que el resto, porque es la primera ejecucion donde se compila y valida las operaciones

despues en las siguientes como esta todo cacheado por eso es mas rapido

quizas poner algun progressbar o manesaje indicando que esta trabajando ayude a indicar que demorara un rato el proceso

saludos

JOSÉ ANTONIO dijo...

Hola Leandro estoy trabajando de la siguiente manera:
tengo estas 3 consultas de diferentes tablas relacionadas con un campo
sql = "SELECT sede_name as sede," _
+ "facu_name as facultad,facu_unac as uni_acade,facu_menc as mencion," _
+ "date_format(dage_ano,'%d/%M/%Y') as fecha," _
+ "peri_name as periodo, " _
+ "moda_name as modalidad, " _
+ "seme_name as semestre, " _
+ "asig_name as asignatura,asig_id, " _
+ "doce_name as docente, " _
+ "dage_desc as desc_materia, " _
+ "dage_obge as obj_general, " _
+ "dage_cope as cope_perf_egreso, " _
+ "evtx_name as eval_resultados, " _
+ "auto_sude as subdecano, auto_dica as dir_carrera " _
+ "FROM datos_generales " _
+ "inner join sede on sede_id = dage_sede " _
+ "inner join facultad on facu_id = dage_facu " _
+ "inner join periodo on peri_id = dage_peri " _
+ "inner join modalidad on moda_id = dage_moda " _
+ "inner join semestres on seme_id = dage_seme " _
+ "inner join asignatura on asig_id = dage_asig " _
+ "inner join docente on doce_id = dage_doce " _
+ "inner join evtx on evtx_id = dage_evre " _
+ "inner join autoridades on auto_facu = dage_facu and auto_sede=dage_sede " _
+ "where dage_asig='" + cmbasig.SelectedValue.ToString + "'"
sql1 = "SELECT hoal_asig,hoal_hora as hora, hoal_lune as lunes, hoal_mart as martes," _
+ "hoal_mier as miercoles, hoal_juev as jueves, " _
+ "hoal_vier as viernes, hoal_saba as sabado " _
+ "FROM datos_generales " _
+ "inner join hoal on hoal_asig = dage_asig " _
+ "where dage_asig='" + cmbasig.SelectedValue.ToString + "'"


sql3 = sql + ";" + sql1

y utilizo este proceso para crear un xml

Dim rptdat_gen As New Reportes("datos_generales", sql3)
rptdat_gen.CreateXMLFile(Application.StartupPath)


con estos procesos creo el xml

Public Sub New(ByVal TableName As String, ByVal SQLstring As String)
Me.TableName = TableName
Me.SQLstring = SQLstring
End Sub
Public Function GetDataTable() As DataTable
Dim myDataAdapter As MySqlDataAdapter
Dim myDataSet As New DataSet
Dim myDataTable As DataTable
myDataAdapter = New MySqlDataAdapter(Me.SQLstring, string_coneccion)
myDataAdapter.Fill(myDataSet, Me.TableName)
myDataTable = myDataSet.Tables(Me.TableName)
Return myDataTable
End Function
Public Sub CreateXMLFile(ByVal FilePath As String)
Dim myDataTable As DataTable
myDataTable = Me.GetDataTable()
myDataTable.WriteXmlSchema(FilePath & "\" & Me.TableName & ".xml")
End Sub

luego llamo para cargar el informe en crystal a

Private Sub refresh_report()
Dim rptclientes As New Reportes("datos_generales", sql3)
Dim rptDoc As ReportDocument = New crpsyllabus
Dim myDataTable As DataTable = rptclientes.GetDataTable()
rptDoc.SetDataSource(myDataTable)
frmipmsill.crvsyllabus.ReportSource = rptDoc
End Sub

y solo me carga una tabla, que estoy haciendo mal o como podria mejorarlo, por la atencion de antemano gracias José Antonio

Leandro Tuttini dijo...

hola JOSÉ

que pasa si lanzas los select por separado usando SqlDataAdapter distintos, no veo correcto unir dos SELECT que separas por medio de un punto y coma

aplica al tecnica que uso en este articulo, ejecuta cada select por separado y los cargas en un mismo datatable

saludos

JOSÉ ANTONIO dijo...

Leandro gracias por tu comentario, le comento que hecho por separado por lo cual he creado uno que se llama datos generales y otro horario pero al hacer la subconsulta o subinforme esta me sale vacía solo con la cabecera de los datos y nada mas y la consulta principal si me presentan los datos, desearía mandar el programa por algún medio que Ud. me podría decir; para que tenga mejor la idea de cual es mi problema adjuntandole la base de datos correspondiente

Leandro Tuttini dijo...

hola JOSÉ

pudiste validar que los datatable que asignas al dataset tipado esten cargados con registros?

validaste que el database expert de Crystal este relacionando los datatable de forma correcta
a veces una incorrecta relacion de los datos dentro del reporte crystal puede causar que no se muestren registros

saludos

JOSÉ ANTONIO dijo...

Leandro; te comento, que todo eso lo he hecho ya que lo he realizado paso a paso, y los datos cargan en el cristal las selecciones las relaciones entre la tabla principal y la subtabla tiene relación con el id de la asignatura... esta raro no se como más hacerlo. Saludos José

Leandro Tuttini dijo...

hola JOSÉ

estas validando que los datos esten en secciones diferentes del reporte?

o sea crear un grupo para poner los datos del primer datatable y el detalle en la seccion de Details

tambien podrias ver de primero crear el reporte con un solo datatable y ver que funcione, luego agregar el segundo

al final el DataBase Exprert de crytal pudiste validarlo? esta correcta la relacion

saludos

Sistemas UCC Cañar dijo...

Hola Leandro te comento para ver el paso de la información lo hice en dos reportes por separados y me carga la información, por lo cual en el codigo puedes ver que tengo un refres1 y un refresh con esa informacion los llamo por separado y luego en un sola data y no me funciona, talvez si tienes un poco de tiempo y revisas esos procedimientos a ver si por ahi encuentras algun paso que estoy obviando te agradeceria

Leandro Tuttini dijo...

hola Sistemas UCC Cañar

la verdad no entendi lo que planteas
pareciera haces referencia a un codigo, pero la verdad no se de cual se trata

que seria "un sola data" ? apuntas a un solo dataset tipado


saludos

Mc Bryan dijo...

Hola tengo un problema lo que pasa es que estoy generando un reporte con crystal reports y visual studio 2012 asp - c# pero el reporte que intento generar es una consulta a dos tablas que se encuentran tipadas en el dataset,
Si hago la consulta a una tabla me vota datos pero cuando intento hacerla con dos tablas me genera la hoja en blanco con el nombre de los campos lo que tengo es esto

//la clase de la conexion
ClassConexion con = new ClassConexion();

//el dataset tipado anteriormente con las tablas desde asistente
DataSet1 ds = new DataSet1();

SqlCommand cons = new SqlCommand("select r.nombre,l.usuario from registro r,login l where l.id_usuario = r.id_usuario and l.usuario = 'pepe'");
cons.Connection = con.conectar();
SqlDataAdapter da = new SqlDataAdapter(cons);
da.Fill(ds,"registro");

//el informe tiene los campos a mostrar
Informe3 inf = new Informe3();
inf.SetDataSource(ds);
CrystalReportViewer1.ReportSource = inf;
CrystalReportViewer1.RefreshReport();

Leandro Tuttini dijo...

hola Mc Bryan

en el ejemplo que proporcionas solo veo que cargas un unico datatable del dataset tipado

para cargar el segundo usas el Fill() como:
da2.Fill(ds,"nombresegundatabla");

revisaste el DataBase Expert de Crystal para ver si la relacion entre las tablas que reconoce el reporte estan correctas

saludos

Unknown dijo...

Estimado, he seguido tu ejemplo sin problemas, consulta; uno de los datatable posee los datos;
-nombre1
-direccion1
-nombre2
-direccion2
Necesito hacer un texto en Crystal que represente:
"Senor 'nombre1' ubicado en 'direccion1' y el Señor 'nombre2' ubicado en 'direccion2'...Señor 'n'"
He intentado por medio de una formula la cual contiene un ciclo 'For Next', pero no logro cambiar el indice del campo ({nombre1}(i)). Duda; Como es posible recorrer un datatable en Crystal reports e incrementar el indice, mostrando cada uno de los registros ?.
agradecería tu ayuda.

Leandro Tuttini dijo...

hola Unknown

si defines este template

Senor ubicado en

en el seccion de detalle, pondrias los campos en los lugares de nombre y direccion

por supuesto se generara uno debajo del otro

saludos