Bind DataTable to RDLC and ReportViewer - vb.net

I have read every single SO question and online article regarding this, and I get confused in a couple different instances.
As my project sits, I have tried to create a Report (Report2.rdlc) manually and drag different fields from DataSources onto the report, and use that report as the data source for the ReportViewer. This did not work. I need to use the DataTable I created from a SqlDataAdapterbecause it decrypts specific rows. I tried creating a DataSet and filling it with the DataTable, however I was unable to perform that, also.
I don't understand: if I have a ReportViewer control on a
WinForm, what all I need in my code to bind a data source to it.
Is the code even creating a report and utilizing the report for
the ReportViewer?
The DataTable name is dt and the ReportViewer control is rv1.
Here's the code I have been toying around with, however I am not sure what to put as the Report Path
Dim RDS1 As ReportDataSource = New ReportDataSource("Test Report", dt)
rv1.LocalReport.DataSources.Clear()
rv1.ProcessingMode = ProcessingMode.Local
rv1.LocalReport.EnableExternalImages = True
rv1.LocalReport.ReportEmbeddedResource = "Your Report Path"
rv1.LocalReport.DataSources.Add(RDS1)`.
The worst part is, the ReportViewer just shows up blank. There are no errors or any indicators as to what could be going wrong.
The information within the DataTable dt is all correct (verified by viewing it in a DGV). I am just trying to use that data in a Report / ReportViewer.
Does anyone have any advice? I cannot seem to catch a break on this issue.
Note: Exporting to Excel is not an option. There are encrypted values that require decryption. The report needs to be printable.
Edit: Here is how I populate the DataTable:
Dim cmd As New SqlCommand
cmd.CommandText = "Select * FROM Participant " & _
"WHERE FIRST_NM_TXT = #searchFirst " & _
"OR LAST_NM_TXT = #searchLast"
cmd.Parameters.AddWithValue("#searchFirst", SearchFirstTxt.Text)
cmd.Parameters.AddWithValue("#searchLast", SearchLastTxt.Text)
Dim adapter As New SqlDataAdapter(cmd)
adapter.Fill(dt)
So, here we have the DataTable with the correct data in it. I have then gone to the Project Name, Added a new Report (Report1.rdlc), and from here I am unsure of the next steps. If I create a DataSet dynamically, should I see it in this window?
Since this seems to be a popular thread, I'll explain how I was able to do this in quick/easy steps.
Right click on your porject -> Add New Item -> Selection Report.rdlc
Top left (Data Source) -> New -> Dataset (select Database [Next ->] Dataset [Next ->] Your DB connection.
"Choose your database objects" screen -> Select Tables
"Choose the dataset" screen -> This will be reset at run time. Make sure you remember the name of this Dataset, because it will be used in the code.
Add ReportViewer control (under Reporting) to the form. Select reportviewer control and go to properties (bottom right pane in VS). Select Local Report's property and set ReportEmbeddedResource to point to the report path we just created. ** ProjectName.ReportName.rdlc**
Peform the usual:
Public DataSet FillDS()
//Try Catch block & other code omitted
Dim cmd As New SqlCommand
cmd.CommandText = "Select * FROM Participant " & _
"WHERE FIRST_NM_TXT = #searchFirst " & _
"OR LAST_NM_TXT = #searchLast"
cmd.Parameters.AddWithValue("#searchFirst", SearchFirstTxt.Text)
cmd.Parameters.AddWithValue("#searchLast", SearchLastTxt.Text)
Dim adapter As New SqlDataAdapter(cmd)
adapter.Fill(dt)
Then, we bind the datasource at run time.
DataSet yourDS = FillDS();
ReportDataSource rds = New ReportDataSource("YourDataSetNameFromStep4", yourDS.Tables[0]);
yourReportViewerName.localreport.datasources.clear();
yourReportViewerName.localreport.datasources.add(rds);
yourReportViewerName.refreshreport();
If there is something I could post in here to help anyone else, let me know.

Some things to check:
"Test Report" must be the name used in the report designer. It's case sensitive.
The dt must match the name used in the report designer too
"Your report Path" should be of the form "namespace.reportname.rdlc" . It's case sensitive.
EDIT:
The approach I normally use utilises an extra layer, in the form of a BindingSource as follows:
Fill a strongly-typed dataset using the ad-hoc query and a SqlDataAdapter.
Dim a Bindingsource and set its DataSource to the dataset and its DataMember to the table name.
Dim a ReportDataSource and set its name to the name used in the report designer, and its value to the BindingSource
eg
Using cn As New SqlConnection(gcs)
cn.Open()
Dim sa As New SqlDataAdapter(sql, cn)
sa.SelectCommand.CommandTimeout = cGlobals.ReportTimeout
sa.Fill(ds, "Foos")
End Using
bs.DataSource = ds
bs.DataMember = "Foos"
Dim rds As New ReportDataSource
rds.Name = "dsFooList_Foos"
rds.Value = bs
rv1.LocalReport.DataSources.Add(rds)
Me.Show()
rv1.RefreshReport()
Edit 2: At the point in your screenshot, drop down the datasources and pick the one you want. It will then appear in the Report Data window, which may be hiding in the 'View' menu (it's only there when you're working with a report) Then you can add a Table to the report from the toolbox, and then drag the fields from the Report Data window to the table cells.

something similar I have made for my "report loader", please check this link, it is written in C# but it will give you an idea how to do it.
How to bind dynamically datasource to reportviewer on windows forms c#

Related

Filtering by ID column

I am trying to filter a table from Ms access DB in visual studio by ID (PID) column but I can't figure out how to convert int to string, or to make it work.
Any ideas please.
con.ConnectionString = dbProvider & dbSource
con.Open()
If PIDfindTextBox.Text = "" Then
MessageBox.Show("Please enter a Patient ID number")
Else
PatienrocordBindingSource.Filter = "((PID,'system.string') like '" & PIDfindTextBox.Text & "')"
If PatienrocordBindingSource.Count <> 0 Then
With dataGridView1.DataSource = PatienrocordBindingSource
End With
Else
MessageBox.Show("Searched Patient ID was not found")
PatienrocordBindingSource.Filter = Nothing
End If
End If
End Sub
Your code is very confused. It opens a database connection then sets a bindingsource filter, this isn't really how things go
A bindingsource is a device that sits between a model of data such as a datatable (which is not a table in a database) and a UI element such as a datagridview or other controls. The bindingsource can filter the data it finds in the model. None of this is anything to do with filling the model up with data in the first place, which often is done by pulling it out of a database
You can probably avoid interacting with a database connection entirely; if you use an OledbDataAdapter you can pull data out of your database and load it into a datatable in your program's memory
You thus have a choice of where to filter your data. You either load the entire database into your program's memory and then use bindingsource filter to show just the one if you want - all the data lives in the datatable and only some of it passes through the bindingsource ..
Or you only download some of the data out of the database and into the datatable, and then you don't need to filter it in the bindingsource
You can also take a hybrid approach of loading, say, 10 records into the datatable and then filtering In the bindingsource
Choose your scenario - most people opt for the middle one where you just download the data you need. There are plenty of examples out there but as a rough template, searching a database table by I'd and pulling the results would look like:
Dim da as New OleDbDataAdapter("SELECT * FROM Person WHERE Id =?", "connection string here")
da.SelectCommand.Parameters.AddWithValue("id", Convert.ToInt32(idTextbox.Text))
Dim dt as New DataTable
da.Fill(dt)
bindingsource.DataSource = dt
If you had 10 rows in your datatable and wanted to filter to just some one id
bindingsource.Filter = "[Id] = " & idFilterTextBox.Text
You don't need to use both of these approaches; use the one that is right for your context

VB.Net how to use a ReportViewer [duplicate]

I have read every single SO question and online article regarding this, and I get confused in a couple different instances.
As my project sits, I have tried to create a Report (Report2.rdlc) manually and drag different fields from DataSources onto the report, and use that report as the data source for the ReportViewer. This did not work. I need to use the DataTable I created from a SqlDataAdapterbecause it decrypts specific rows. I tried creating a DataSet and filling it with the DataTable, however I was unable to perform that, also.
I don't understand: if I have a ReportViewer control on a
WinForm, what all I need in my code to bind a data source to it.
Is the code even creating a report and utilizing the report for
the ReportViewer?
The DataTable name is dt and the ReportViewer control is rv1.
Here's the code I have been toying around with, however I am not sure what to put as the Report Path
Dim RDS1 As ReportDataSource = New ReportDataSource("Test Report", dt)
rv1.LocalReport.DataSources.Clear()
rv1.ProcessingMode = ProcessingMode.Local
rv1.LocalReport.EnableExternalImages = True
rv1.LocalReport.ReportEmbeddedResource = "Your Report Path"
rv1.LocalReport.DataSources.Add(RDS1)`.
The worst part is, the ReportViewer just shows up blank. There are no errors or any indicators as to what could be going wrong.
The information within the DataTable dt is all correct (verified by viewing it in a DGV). I am just trying to use that data in a Report / ReportViewer.
Does anyone have any advice? I cannot seem to catch a break on this issue.
Note: Exporting to Excel is not an option. There are encrypted values that require decryption. The report needs to be printable.
Edit: Here is how I populate the DataTable:
Dim cmd As New SqlCommand
cmd.CommandText = "Select * FROM Participant " & _
"WHERE FIRST_NM_TXT = #searchFirst " & _
"OR LAST_NM_TXT = #searchLast"
cmd.Parameters.AddWithValue("#searchFirst", SearchFirstTxt.Text)
cmd.Parameters.AddWithValue("#searchLast", SearchLastTxt.Text)
Dim adapter As New SqlDataAdapter(cmd)
adapter.Fill(dt)
So, here we have the DataTable with the correct data in it. I have then gone to the Project Name, Added a new Report (Report1.rdlc), and from here I am unsure of the next steps. If I create a DataSet dynamically, should I see it in this window?
Since this seems to be a popular thread, I'll explain how I was able to do this in quick/easy steps.
Right click on your porject -> Add New Item -> Selection Report.rdlc
Top left (Data Source) -> New -> Dataset (select Database [Next ->] Dataset [Next ->] Your DB connection.
"Choose your database objects" screen -> Select Tables
"Choose the dataset" screen -> This will be reset at run time. Make sure you remember the name of this Dataset, because it will be used in the code.
Add ReportViewer control (under Reporting) to the form. Select reportviewer control and go to properties (bottom right pane in VS). Select Local Report's property and set ReportEmbeddedResource to point to the report path we just created. ** ProjectName.ReportName.rdlc**
Peform the usual:
Public DataSet FillDS()
//Try Catch block & other code omitted
Dim cmd As New SqlCommand
cmd.CommandText = "Select * FROM Participant " & _
"WHERE FIRST_NM_TXT = #searchFirst " & _
"OR LAST_NM_TXT = #searchLast"
cmd.Parameters.AddWithValue("#searchFirst", SearchFirstTxt.Text)
cmd.Parameters.AddWithValue("#searchLast", SearchLastTxt.Text)
Dim adapter As New SqlDataAdapter(cmd)
adapter.Fill(dt)
Then, we bind the datasource at run time.
DataSet yourDS = FillDS();
ReportDataSource rds = New ReportDataSource("YourDataSetNameFromStep4", yourDS.Tables[0]);
yourReportViewerName.localreport.datasources.clear();
yourReportViewerName.localreport.datasources.add(rds);
yourReportViewerName.refreshreport();
If there is something I could post in here to help anyone else, let me know.
Some things to check:
"Test Report" must be the name used in the report designer. It's case sensitive.
The dt must match the name used in the report designer too
"Your report Path" should be of the form "namespace.reportname.rdlc" . It's case sensitive.
EDIT:
The approach I normally use utilises an extra layer, in the form of a BindingSource as follows:
Fill a strongly-typed dataset using the ad-hoc query and a SqlDataAdapter.
Dim a Bindingsource and set its DataSource to the dataset and its DataMember to the table name.
Dim a ReportDataSource and set its name to the name used in the report designer, and its value to the BindingSource
eg
Using cn As New SqlConnection(gcs)
cn.Open()
Dim sa As New SqlDataAdapter(sql, cn)
sa.SelectCommand.CommandTimeout = cGlobals.ReportTimeout
sa.Fill(ds, "Foos")
End Using
bs.DataSource = ds
bs.DataMember = "Foos"
Dim rds As New ReportDataSource
rds.Name = "dsFooList_Foos"
rds.Value = bs
rv1.LocalReport.DataSources.Add(rds)
Me.Show()
rv1.RefreshReport()
Edit 2: At the point in your screenshot, drop down the datasources and pick the one you want. It will then appear in the Report Data window, which may be hiding in the 'View' menu (it's only there when you're working with a report) Then you can add a Table to the report from the toolbox, and then drag the fields from the Report Data window to the table cells.
something similar I have made for my "report loader", please check this link, it is written in C# but it will give you an idea how to do it.
How to bind dynamically datasource to reportviewer on windows forms c#

Editing DataGridView data and updating changes directly into MySQL database

I want to save the changes that have made in the datagridview. I have code for adding the existing entries on the datagridview but I don't know how to update the changes made on datagridview
here is the code i am using to for adding the datagridview entries to the database
Public Sub ADD_DGV_CMD(SENDER As String)`
For Each row As DataGridViewRow In ALL_BILL_FRM.DataGridView1.Rows
Dim constring As String = "server=localhost; user=root; password=Masoom1; database=airtech_db; convert zero datetime=true;"
Using con As New MySqlConnection(constring)
Using cmd As New MySqlCommand("Insert into `all_bills` values(null,#Supplier_Name,#Bill_No,#Bill_Type,#Bill_Amount,#Bill_Date);", con)
cmd.Parameters.AddWithValue("#Supplier_Name", row.Cells(1).Value)
cmd.Parameters.AddWithValue("#Bill_No", row.Cells(2).Value)
cmd.Parameters.AddWithValue("#Bill_Type", row.Cells(3).Value)
cmd.Parameters.AddWithValue("#Bill_Amount", row.Cells(4).Value)
cmd.Parameters.AddWithValue("#Bill_Date", row.Cells(5).Value)
con.Open()
cmd.ExecuteNonQuery()
con.Close()
End Using
End Using
Next
MessageBox.Show("Records inserted.")
End Sub
You keep adding parameters in a loop. If your table contains more than one then all the parameters will be added again. They don't replace the existing ones, they supplement them, hence the "already added" error
Move your parameter adds to outside the loop. Chef get the way you work so that he parameter values are updated in the loop..
I would say "you should do:"
.Parameters("#Supplier_Name").Value = row.Cells(1).Value.ToString
..inside the loop, but what you should actually do is toss this lot out and take a look at using a strongly typed dataset, dapper or entity framework. If you're keen to carry on filling your button click handlers with SQL, dapper lets you do that but you might well get more out of something more high level
The short short version of using datasets is:
add a dataset to your project
open it, right click the surface and choose Add TableAdapter
connect to MySQL, ensure you have installed both the driver and the visual studio tools
enter SELECT * FROM all_bills as the query, finish the wizard
save the dataset
open the forms designer
open the data sources window (view menu, other windows)
drag the grid representing your table out of the data sources window and drop it on the form
run the project
Your grid will load and be able to to read and write the dB, not a single line of code written (by you; visual studio wrote a whole lot behind the scenes - you can see it in various .Designer.vb files)!
Public Class MAIN_FRM
Dim changes_counter As Integer, SEARCH_TYPE As String
Dim con As New MySqlConnection("server=localhost; user=root; password=Masoom1; database=airtech_db;")
Dim da As New MySqlDataAdapter("Select * from all_bills;", con)
Dim ds As New DataSet
Dim cmdBuilder As New MySqlCommandBuilder
Dim LOAD_CMD_CALL As Boolean
Private Sub UPDATE_BTN_Click(sender As Object, e As EventArgs) Handles UPDATE_BTN.Click
Try
cmdBuilder = New MySqlCommandBuilder(da)
ds = ds.GetChanges()
If ds IsNot Nothing Then
da.Update(ds)
MsgBox("Changes Done")
End If
Catch ex As Exception
MsgBox(ex.ToString)
End Try
END SUB

How to get the result of stored procedure with parameter and use for Crystal Report in VB.Net

My IDE is MS Visual Studio 2008.
I just want to ask how can I get the result of a store procedure from MS Access using VB.Net and use the result in a Crystal Report.
I have a Windows Application Project that requires this function.
Thanks in advance for the answer.
Building on the code from the previous answer on executing a stored procedure, you can create a dataset and then pass this dataset to Crystal Reports.
In order to design the report in Crystal Reports, you should take the following steps (the details for each step can easily be found in the Visual Studio help or online):
1) Add a connection to the access database in server explorer.
2) Create a new DataSet for the stored procedure (query) within visual studio. We'll assume that this is called DataSet1.
3) Create your Crystal Report and have it use this new DataSet. We'll assume that this report is called CyrstalReport1.
4) Add a CrystalReportViewer to your form that you are displaying the reports on. We'll assume the viewer is called CrystalReportViewer1.
5) Add the following code to your form to execute the query, fill the dataset, and load the crystal report with the dataset.
Dim oReport As New CrystalReport1
Dim dsDataSet as New DataSet1
Using conn As New OleDbConnection()
conn.ConnectionString = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=C:\myaccess.mdb"
conn.Open()
Using cmd As New OleDbCommand()
cmd.CommandText = "NameOfTheQuery"
cmd.CommandType = CommandType.StoredProcedure
' Note: You can also use CommandType.TableDirect
cmd.Connection = conn
Using oAdapter As New OleDbDataAdapter
oAdapter.SelectCommand = cmd
oAdapter.Fill(dsData)
' Set the data source for the report to the new dataset
oReport.SetDataSource(dsDataSet)
' Set the report into the viewer
CrystalReportViewer1.ReportSource = oReport
End Using
conn.Close()
End Using
End Using

Using TableAdapter to insert rows into a dataset does not do anything

I have a question similar to this one, but reading the (accepted) answer didn't give me much insight, so I'm hoping to state it more clearly and get a clearer response back.
I'm attempting to insert a data row into a table. I'm using TableAdapter's custom "insert nonQuery" that I wrote (it works, I tested) to accept some parameters. I'm fairly new to this business of communication with a database via .NET and what I'm doing is probably wrong by design. My questions are why is it wrong and what's the right way to do it? Both are equally important, IMO.
Here's some sample VB code I wrote:
Dim arraysTableAdapter As New UnitTestsDataSetTableAdapters.ArraysTableAdapter
Try
arraysTableAdapter.InsertArray("Test Array", 2, 1, 2, "Test user")
Catch ex As SqlException
MsgBox("Error occured when trying to add new array." _
& vbNewLine & vbNewLine _
& ex.Message)
End Try
...and that's pretty much it. There is no exception raised, my table does not get a new row inserted. Everything is just the way it was before I called the InsertArray method. When I test my query in the QueryBuilder with the same parameters, a new row gets added to the database.
Now, I do understand some of the reasons this would not work. I understand that I need to create and select a row in my DataSet (no idea how to do it) in order to tell the TableAdapter what it's adding the data to. Or at least I got that impression from reading the vast abyss of forums.
I would really like to use TableAdapter at some point, because it knows that .InsertArray exists and it knows which parameters it likes. I could try and do it using
Dim con As New SqlConnection
Dim cmd As New SqlCommand
con.ConnectionString = connString
con.Open()
cmd.CommandText = "INSERT ...... all that jazz"
but it's not nearly clean enough for how clean I like my code to be. So, is there any way to do what I'm trying to do the way I'm doing it? In other words, how do I use the neat structure of a TableAdapter to communicate to my DataSet and put a new row in it?
Thanks in advance!
There were two things that were wrong:
(minor issue) I did not have a DataTable filled from the TableAdapter (see code below)
(major, sneaky issue) My method worked from the very beginning. There is nothing extra to be added except for the line above. However, the ConnectionString of arraysTableAdapter was pointing my program (automatically, by default) to a wrong location. Once I manually set the ConnectionString, it worked perfectly.
Here's my complete code:
Dim connString As String = "Some correct connection string"
Dim arraysDataTable As New SpeakerTestsDataSet.ArraysDataTable
Dim arraysTableAdapter As New UnitTestsDataSetTableAdapters.ArraysTableAdapter
'Set the correct connection string'
arraysTableAdapter.Connection.ConnectionString = conn
'Fill table from the adapter'
arraysTableAdapter.Fill(arraysDataTable)
Try
arraysTableAdapter.Insert("Test", 2, 1, 2, Now, Now, "Me")
Catch ex As Exception
MsgBox("Error occured when trying to add new array." _
& vbNewLine & vbNewLine _
& ex.Message)
End Try
The accepted answer in the question you linked to is correct, but sometimes saying it in different words helps:
A TableAdapter is used to communicate between a DataTable (there can be one or more DataTables in a DataSet) and a database. It can pull data from a database and add it to a DataTable and it can send data from a DataTable to the database. It's purpose is to create and execute the SQL code required to make this communication work.
You are trying to use the TableAdapter to directly add data to your DataTable. This will not work. Instead, you should use the methods that come with the DataTable to add a new row to the DataTable and then (if necessary) use your TableAdapter to send that row to a database.
For instance, with a Dataset called DataSet1 that contains a DataTable called DataTable1 that has three text columns you can add a record like this:
Dim d As New DataSet1
d.DataTable1.AddDataTable1Row("value1", "value2", "value3")
That AddDataTable1Row method is automatically created for you, and I think is what you are looking for.