Cstruire report con Crystal Report

lunedì 18 agosto 2008 - 14.06

Mau67 Profilo | Expert

Salve, ho la necessità di costruire dei report con Crystal Report incluso nell'ide di Visual Studio 2005 Professional, uso come tabelle SQLServer2005 express.

Detto ciò dovrei costruire più report senza dovermi agganciare al database in modo dinamico ma usando possibilmente la stessa tecnica che stò usando per far leggere i dati dalle tabelle al form.

Vi posto il codice che uso all'interno dei form per favi capire cosa intendo

Imports System
Imports System.Data
Imports System.Data.SqlClient
Imports System.Collections.Generic
Imports System.Text
Imports System.IO

Public Class SelezionaBanca

' Declare objects...

Private Const FILE_NAME As String = "C:\myConnectionString.txt"

Dim objDataReader As System.Data.SqlClient.SqlDataReader
Dim cmd As New System.Data.SqlClient.SqlCommand


Private Sub SelezionaBanca_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load


If Not File.Exists(FILE_NAME) Then
MsgBox(FILE_NAME & " does not exist.")
Return
End If
Dim sr As StreamReader = File.OpenText(FILE_NAME)
Dim sqlString As String
sqlString = sr.ReadLine()
Me.ToolStripStatusLabel2.Text = (sqlString) 'Questo è solo per verificare!
sr.Close()

Dim objConnection As New SqlConnection(sqlString)

Try


objConnection.Open()

cmd.CommandText = "SELECT Abi, IstitutoCredito, Cab," & _
"Agenzia, IndirizzoIstituto, LuogoIstituto," & _
"Cap, Prov FROM Banca

cmd.Connection = objConnection

objDataReader = cmd.ExecuteReader

While objDataReader.Read

' Add new bindings to the DataView object...
ListBox1.Items.Add(objDataReader.Item("IstitutoCredito") & Chr(9) & "" & objDataReader.Item("Agenzia") & Chr(9) & "" & objDataReader.Item("IndirizzoIstituto") & Chr(9) & "" & objDataReader.Item("LuogoIstituto") & Chr(9) & "" & objDataReader.Item("Cap") & Chr(9) & "" & objDataReader.Item("Prov"))

End While

Catch ex As Exception
MsgBox(ex.Message, MsgBoxStyle.Critical)
End Try
End If
End Class

Ve lo spiego:

Private Const FILE_NAME As String = "C:\myConnectionString.txt" (questa e la stringa dove è memorizzato il percorso dove si trova il database ed è un file di testo)

poi il resto del codice va a leggere i dati nelle tabelle.

Adesso usando la stessa tecnica per legere i dati nelle tabelle con quella stringa di connessione che chiaramente può cambiare se sposto il database, si può fare lo stesso per costruire dei report e quindi
che mi legga i dati dalle tabelle collegandole a quel percorso?

Spero di essermi spiegato bene

Ah sono un principiante ed è la prima volta che uso Crystal report

Grazie in anticipo


Mau67

freeteo Profilo | Guru

ciao,
i dati che passi al report possono provenire da diverse fonti (sia in numero, che in tipologia) quindi il fatto che tu legga da un file di testo, piuttosto che da un db, piuttosto che da un xml o addirittura che ti crei tutto al volo basandoti sul tuo domain model, è del tutto indifferente.
La cosa che serve al report però, è la struttura dei dati che gli passerai, nel senso di dire costruisco un report con 3 campi di tipo stringa,int e datetime, e questi campi (o colonne di un datatable) saranno passati al report, da dove provengano è assolutamente compito della tua applicazione e non fa differenza al Report, basta solo che lo "schema" (quindi la sequenza di campi e la tipologia) sia lo stesso.

Premesso questo concetto fondamentale, nel tuo caso, io proporrei di costruirti il report da design agganciandoti al db che contiene la tabella "Banca" ad esempio, ed estrapolare le colonne che ti interessa poi visualizzare, dall'esperto database.
Non preoccuparti se il db è tuo locale, o è di prova, non importa, i dati glieli passerai con la tua tecnica di leggere la connectiostring.txt e il SqlDataReader, quello che importa qui è far capire al report cosa (e come) deve visualizzare.

Fatto questo disegni il report, lo componi come lo vuoi, e lo salvi.

Nella tua form dove metti il ReportViewer, fai un codice (nel load magari) di questo tipo:

...codice tuo di prima per la connessione... cmd.CommandText = "SELECT Abi, IstitutoCredito, Cab," & _ "Agenzia, IndirizzoIstituto, LuogoIstituto," & _ "Cap, Prov FROM Banca cmd.Connection = objConnection objDataReader = cmd.ExecuteReader '--- carichiamo colonne/righe in una datatable Dim tabella as new DataTable() tabella.Load(objDataReader) '--- adesso carichi il report e gli passi i dati contenuti nella datatable Dim mioreport as new ReportDocument() mioreport.Load("c:\...\mioreport.rpt") mioreport.SetDataSource(tabella) CrystalReportViewer1.ReportSource = mioreport

la cosa è abbastanza semplice, l'unica cosa da stare attenti è appunto costruire il report con le colonne che poi si troveranno nella datatable, altrimenti avrai un errore a runtime.

Se vuoi capire meglio, puoi guardare questo:
http://www.dotnethell.it/articles/Crystal-Reports-Integration-Windows-Form.aspx
dove trovi anche un esempio già pronto da scaricare e vedere il caso in cui i dati vengono passati tramite datatable.
ciao.

Matteo Raumer
[MCAD .net]
http://blogs.dotnethell.it/freeteo

Mau67 Profilo | Expert

funzione correttamente grazie,

Però solo quando istanzi una sola tabella! ma quando le tabelle sono due o più di due?

Ecco il codice dove sbaglio

If Not File.Exists(FILE_NAME) Then
MsgBox(FILE_NAME & " does not exist.")
Return
End If
Dim sr As StreamReader = File.OpenText(FILE_NAME)
Dim sqlString As String
sqlString = sr.ReadLine()
Me.ToolStripStatusLabel2.Text = (sqlString) 'Questo è solo per verificare!
sr.Close()

Dim objConnection As New SqlConnection(sqlString)




objConnection.Open()

cmd.CommandText = " SELECT Anagrafica.IDUtente, Anagrafica.CodiceFiscale, Anagrafica.ForzaArmata," & _
"Anagrafica.Categoria, Anagrafica.Grado, Anagrafica.LivParCod," & _
"Anagrafica.Cognome, Anagrafica.Nome, Presenze.IDPresenza, Presenze.Dal, Presenze.Al, Presenze.Giorni," & _
"Presenze.Mese, Presenze.Anno, Presenze.Motivo" & _
" FROM Anagrafica JOIN Presenze ON Anagrafica.IDUtente = Presenze.IDUtente"

cmd.Connection = objConnection

objDataReader = cmd.ExecuteReader

Dim tabella As New DataTable
tabella.Load(objDataReader)

Dim mioreport As New ReportDocument
mioreport.Load("C:\Documents and Settings\Mio\Documenti\Visual Studio 2005\Projects\MITO\MITO\rptPresenza.rpt")
mioreport.SetDataSource(tabella)

CrystalReportViewer1.ReportSource = mioreport
Mau67

Mau67 Profilo | Expert

la select con più tabelle mi genera un errore dicendo che non trova la tabella presenze come devo fare perchè crystal report funzioni con più tabelle?

Grazie
Mau67

freeteo Profilo | Guru

ciao,
per più tabelle devi caricare varie DataTable, e poi passarle alle sue relative (quelle aggiunte e utilizzate nel report a design):
... report.Database.Tables[0].SetDataSource(... ...
come vedi, le imposti tabella per tabella.Puoi anche usare un dataset, ma questo modo mi è sempre sembrato il più "preciso" per avere controllo e possibilità di verificare anche in debug se c'è qualcosa che non va...

ps: nel report a design-time devi linkarle ovviamente
ciao.

Matteo Raumer
[MCAD .net]
http://blogs.dotnethell.it/freeteo

Mau67 Profilo | Expert

Scusa ma non credo di aver capito potresti farmi un esempio usando il codice che ho postato, sai sono un principiante
te ne sarei grato.

Grazie
Mau67

freeteo Profilo | Guru

ciao,
allora con 2 tabelle nel report (intendo che hai fatto un report aggiungendo 2 o piu tabelle dall'esperto database di crystal) poi devi passare i dati alle 2 tabelle da codice:
...come prima, carichi i dati in una datatable mioreport.Database.Tables("tabella1").SetDataSource(datatable1) ...come prima, carichi i dati in una datatable mioreport.Database.Tables("tabella2").SetDataSource(datatable2)

etcc... dove "tabella2" è il nome della tabella del report, e "datatable2" è una DataTable con i dati che ti servono.


Se quello che vuoi fare tu, è creare il report con "una join" come vedo dalla tua stringa sql, allora la tabella è sempre una, ovvero crei il report aggiungendo non una tabella intera, ma un "comando" (che è proprio la stringa sql che poi usi come query per riempire la datatable):

564x393 83Kb

Fatto questo, il report avrà una tabella sola, con i campi comuni delle 2 tabelle, ovvero quello che torna la query.
Adesso ti basta riempire la datatable da codice, e poi passargliela, ma come ti dicevo in questo caso la tabella del report è una, e uno è il "setDataSource" che gli fai, come abbiamo detto il post di prima.

Forse è quest'ultimo il caso che intendi dire tu per "2 tabelle" se non ho capito male
ciao.

Matteo Raumer
[MCAD .net]
http://blogs.dotnethell.it/freeteo

Mau67 Profilo | Expert

Scusa ma non riesco ancora a capire

allora quello che voglio fare e proprio questo

Se quello che vuoi fare tu, è creare il report con "una join" come vedo dalla tua stringa sql, allora la tabella è sempre una, ovvero crei il report aggiungendo non una tabella intera, ma un "comando" (che è proprio la stringa sql che poi usi come query per riempire la datatable):



564x393 83Kb

Fatto questo, il report avrà una tabella sola, con i campi comuni delle 2 tabelle, ovvero quello che torna la query.
Adesso ti basta riempire la datatable da codice, e poi passargliela, ma come ti dicevo in questo caso la tabella del report è una, e uno è il "setDataSource" che gli fai, come abbiamo detto il post di prima.


QUESTO E' IL CODICE CHE HO USATO:


Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click

Dim objDataReader As System.Data.SqlClient.SqlDataReader
Dim cmd As New System.Data.SqlClient.SqlCommand

If Not File.Exists(FILE_NAME) Then
MsgBox(FILE_NAME & " does not exist.")
Return
End If
Dim sr As StreamReader = File.OpenText(FILE_NAME)
Dim sqlString As String
sqlString = sr.ReadLine()
Me.ToolStripStatusLabel2.Text = (sqlString) 'Questo è solo per verificare!
sr.Close()

Dim objConnection As New SqlConnection(sqlString)




objConnection.Open()

cmd.CommandText = " SELECT Anagrafica.IDUtente, Anagrafica.CodiceFiscale, Anagrafica.ForzaArmata," & _
"Anagrafica.Categoria, Anagrafica.Grado, Anagrafica.LivParCod," & _
"Anagrafica.Cognome, Anagrafica.Nome, Presenze.IDPresenza, Presenze.Dal, Presenze.Al, Presenze.Giorni," & _
"Presenze.Mese, Presenze.Anno, Presenze.Motivo" & _
" FROM Anagrafica JOIN Presenze ON Anagrafica.IDUtente = Presenze.IDUtente"



cmd.Connection = objConnection

objDataReader = cmd.ExecuteReader

Dim tabella As New DataTable
tabella.Load(objDataReader)

Dim mioreport As New ReportDocument
mioreport.Load("C:\Documents and Settings\Mio\Documenti\Visual Studio 2005\Projects\MITO\MITO\rptPresenza.rpt")
mioreport.Database.Tables("tabella").SetDataSource(tabella) QUI MI GENERA QUESTO ERRORE (Indice non valido. (Eccezione da HRESULT: 0x8002000B (DISP_E_BADINDEX)))


CrystalReportViewer1.ReportSource = mioreport
End Sub


Mi genera lo stesso errore anche se al posto di tabella gli scrivo la SELECT.

Cosa devo fare?

Grazie per la pazienza


Mau67

freeteo Profilo | Guru

ciao,
ma tu hai creato il report impostando il comando come tabella?
la stringa "tabella" che vedi nel codice report.Database.Tables("tabella") è il nome della tabella, tu devi mettere quello corretto che hai nel design del report (tipicamente "comando" ma cmq lo vedi nel nodo dove hai i campi da trascinarci dentro).

Il resto del codice è corretto, eventualmente allegami il report che controllo.Grazie.
ciao.

Matteo Raumer
[MCAD .net]
http://blogs.dotnethell.it/freeteo

Mau67 Profilo | Expert

Ti ho allegato il report, non riesco a visualizzare

Grazie per l'aiuto
Mau67

freeteo Profilo | Guru

ho visto il report ed ho visto che nel field explorer hai 2 tabelle e qui già non ci siamo (almeno perchè tu mi hai detto che gli passi la join tramite SqlCommand etc...).

Come ti dicevo prima, devi fare il report usando un comando e non aggiungendo le 2 tabelle, quindi a regime il report dovrebbe essere con una sola tabella, risultato della stringa sql.
Per farlo fai così:

800x600 224Kb


Quando hai il report a posto, puoi usare il codice che hai messo prima, usando il nome corretto di tabella.
ciao.

Matteo Raumer
[MCAD .net]
http://blogs.dotnethell.it/freeteo

Mau67 Profilo | Expert

Ho fatto come mi hai detto funziona

Ma con un problema Il report mi visualizza i dati di un solo amministrato nel corpo e i dati di tutti gli altri inseriti nei dettagli senza agganciarli in base alla chiave di relazione

Cosa devo fare?
Mau67

freeteo Profilo | Guru

>Ho fatto come mi hai detto funziona
ok


>Ma con un problema Il report mi visualizza i dati di un solo
>amministrato nel corpo e i dati di tutti gli altri inseriti nei
>dettagli senza agganciarli in base alla chiave di relazione
allora qui devi ragionare usando i dati che ti si presentano come risultato della query, ovvero hai dei valori relativi ai campi comuni della query che hanno sicuramente alcuni valori duplicati.
Il report per gestire questa cosa, ti fornisce i raggruppamenti, quindi devi aggiungere al report dei raggruppamenti, tipicamente per i dati di testata e mettere questi campi nell'instestazione del gruppo, e i dati di dettaglio invece nella sezione dettagli (che come vedrai andranno sempre dentro ai vari raggruppamenti).

ps: i gruppi possono essere annidati, quindi puoi fare dei raggruppamenti in cascata.

ciao.

Matteo Raumer
[MCAD .net]
http://blogs.dotnethell.it/freeteo

Mau67 Profilo | Expert

Ok perfetto grazie


Mau67
Partecipa anche tu! Registrati!
Hai bisogno di aiuto ?
Perchè non ti registri subito?

Dopo esserti registrato potrai chiedere
aiuto sul nostro Forum oppure aiutare gli altri

Consulta le Stanze disponibili.

Registrati ora !
Copyright © dotNetHell.it 2002-2024
Running on Windows Server 2008 R2 Standard, SQL Server 2012 & ASP.NET 3.5