Using one dataset in many forms - vb.net

I am using vb.net to load data from sql server database. I have defined a dataset in my module
and want to use it in many forms Public dsDataset As DataSet. When I load the main form I load the options that are likely to be the same in all the forms like the departments and sections, so that I do not have to load them again in all the forms. When Navigating from main form to an other form I pass this dataset in a the form constructor.
In the main form I am loading these options:
Sub loadOptions()
Dim da As SqlDataAdapter
Dim sql As String
Try
sqlConn = New SqlConnection(connString)
sqlConn.Open()
sql = " select depId, name from DEPARTMENT "
da = New SqlDataAdapter(sql, sqlConn)
da.Fill(dsDataset, "department")
sql = " select select depId, sectionId, name from SECTION "
da = New SqlDataAdapter(sql, sqlConn)
da.Fill(dsDataset, "section")
'----------------------------------------------------------------------
sqlConn.Close()
Catch ex As Exception
sqlConn.Close()
MsgBox(Err.Description)
End Try
End Sub
Then lets say I have printers form where I load data from from the database and use the option in the dsDataset instead of loading them again. I pass the dataset as follows:
Dim printers As frmPrinters = New frmPrinters(dsDataset)
printers.ShowDialog()
and in the printers form I have a constructor as follows:
Sub New(ByRef dsDataset As DataSet)
InitializeComponent()
cmbDepartment.DataSource = dsDataset.Tables("department")
cmbDepartment.DisplayMember = "name"
cmbDepartment.ValueMember = "depId"
cmbSection.DataSource = dsDataset.Tables("section")
cmbSection.DisplayMember = "name"
cmbSection.ValueMember = "sectionId"
End Sub
and load all the printers to the dataset with no problem:
sql = "select * from printer where printerId=" & printerId
daPrinter = New SqlDataAdapter(sql, sqlConn)
daPrinter.Fill(dsDataset, "printer")
dgvPrinters.DataSource = dsDataset.Tables("printers")
Now when I double click any of the printers I go an other form to load the details of that particular printer as follows:
printerId = dgvPrinters.Rows(dgvPrinters.CurrentRow.Index).Cells(0).Value
printerMode = "modify"
Dim printer As New frmPrinter(dsDataset)
printer.ShowDialog()
In the new form I use the same constructor above but the problem happens there. The following error comes:
Value cannot be null.
Parameter name: dataSet
What I am doing wrong?

It doesn't look like you are saving the dsDataset anywhere in your constructor. For example in a private variable. My guess is that inside frmPrinters you will have a public dsDataSet variable which you never set to anything.
So what you should do is the following:
Create a private dsDataSet variable in frmPrinter called _dsDataset:
Private _dsDataset As DataSet
In the constructor do this:
_dsDataset = dsDataset
And finally in the doubleclick event send the private variable:
Dim printer As New frmPrinter(_dsDataset)
And then you should be fine.

Related

Using block - scope issues

I am learning visual basic and OOP on the fly.
This piece of code displays the query results to a combo box on a form...
Dim c = System.Configuration.ConfigurationManager.ConnectionStrings("db").ToString()
Dim daDogs As New SqlDataAdapter ("select dog_type from humane_society with(nolock)",c)
Dim dtdogs As New DataTable
dadogs.Fill(dtdogs)
cboDogs.DataSource = dtdogs
cboDogs.DisplayMember = "dog_type"
when I change it to use a Using block, the combo box is blank
I think it is a scope issue, but I don't know how to fix it. Any productive suggestions would be greatly appreciated. Thanks!
Dim c = System.Configuration.ConfigurationManager.ConnectionStrings("db").ToString()
Using cDog As New SqlConnection(c)
Using cmd As New SqlCommand("select dog_type from humane_society with(nolock)",cDog)
cmd.CommandType = commandtype.Text
Using daDogs As New SqlDataAdapter(cmd)
Using dtDogs As New Datatable`enter code here`
daDogs.Fill(dtDogs)
' MsgBox(dtMunic.Rows(500).Field(of string)(0))
cboDogs.DataSource = dtDogs
cboDogs.DisplayMember = "dog_type"
End Using
End Using
End Using
End Using
Not sure what that message box is doing in your code. Remember that a message box halts the code until the user responds. You connection, among other things, is open while the code waits.
You are correct that items declared in a block are scoped to that block.
I have separated your database code from your user interface code.
You can save using blocks by adding a comma and combining more than one object in the block. Behaves the same, just makes the code a bit easier to read.
Private ConStr As String = System.Configuration.ConfigurationManager.ConnectionStrings("db").ToString() '"Your connection string"
Private Function GetDogData() As DataTable
Dim dt As New DataTable
Using cDog As New SqlConnection(ConStr),
cmd As New SqlCommand("select dog_type from humane_society with(nolock)", cDog)
cDog.Open()
Using reader = cmd.ExecuteReader
dt.Load(reader)
End Using
End Using
Return dt
End Function
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim dtDogs = GetDogData()
cboDogs.DataSource = dtDogs
cboDogs.DisplayMember = "dog_type"
End Sub

SqlCommandBuilder Update Command is Generating Command but Not Updating Database From DataGridView

I am inheriting a form class (Form1) for Form 2. Form 1 code works without error. In Form 1, I use SqlCommandBuilder(SQL.DBDA).GetUpdateCommand to generate the update command for my Datagrid to pass to SQL data table which again works perfectly and the table is updated successfully. The SQL command text for Form 1 Update is shown here:
In Form 2, I write the following for the update command, where the only difference is Selecting the Table shown here:
SQL.ExecQuery("SELECT * FROM dtbRateVerse;")
SQL.DBDA.UpdateCommand = New SqlClient.SqlCommandBuilder(SQL.DBDA).GetUpdateCommand
MsgBox(SQL.DBDA.UpdateCommand.CommandText)
SQL.DBDA.Update(SQL.DBDT)
The command text for this update command is shown here:
It is not dissimilar to the successful update command shown in Form1 (image 1). Still, no data is passed to the SQL from the Gridview.
I also tried writing a dynamic Update statement without using the command builder shown below. The text of this statement generates an accurate SQL command but again, nothing passed to the database. This code is shown here:
For i = 1 To colEnd
colName.Add("[" & DataGridView1.Columns(i).HeaderText.ToString & "]")
Next
For i = 1 To colEnd
For y = 0 To Me.DataGridView1.RowCount - 1
For n = 1 To colEnd
gridVals.Add(DataGridView1.Rows(y).Cells(n).Value.ToString)
Next
With Me.DataGridView1
SQL.AddParam("#PrimKey", .Rows(y).Cells(0))
cmdUpdate = "UPDATE " & tbl_Name & " SET " & colName.Item(i - 1) & "=" & gridVals.Item(i - 1) & " WHERE ID=#PrimKey;"
SQL.ExecQuery(cmdUpdate)
End With
Next
Next
If anyone has any ideas/ solutions on what I need to do to get the update command working properly, I'd really appreciate it. Thanks!
Added ExecQuery methdod per request below:
Public Class SQLControl
Private DBConnect As New SqlConnection("SERVER STRING HERE")
Private DBCmd As SqlCommand
'DB DATA
Public DBDA As SqlDataAdapter
Public DBDT As DataTable
'QUERY PARAMETERS
Public Params As New List(Of SqlParameter)
'QUERY STATISTICS
Public RecordCount As Integer
Public Exception As String
Public Sub New()
End Sub
'ALLOW CONNECTION STRING OVERRIDE
Public Sub New(ConnectionString As String)
DBConnect = New SqlConnection(ConnectionString)
End Sub
'EXECUTE QUERY SUB
Public Sub ExecQuery(Query As String)
'RESET QUERY STATS
RecordCount = 0
Exception = ""
Try
DBConnect.Open()
'CREATE DATABASE COMMAND
DBCmd = New SqlCommand(Query, DBConnect)
'LOAD PARAMS INTO DB COMMAND
Params.ForEach(Sub(p) DBCmd.Parameters.Add(p)) 'LAMBDA EXPRESSION
'CLEAR PARAMS LIST
Params.Clear()
'EXECUTE COMMAND & FILL DATASET
DBDT = New DataTable
DBDA = New SqlDataAdapter(DBCmd)
RecordCount = DBDA.Fill(DBDT)
Catch ex As Exception
'CAPTURE ERROR
Exception = "ExecQuery Error: " & vbNewLine & ex.Message
Finally
'CLOSE CONNECTION
If DBConnect.State = ConnectionState.Open Then DBConnect.Close()
End Try
End Sub
'ADD PARAMS
Public Sub AddParam(Name As String, Value As Object)
Dim NewParam As New SqlParameter(Name, Value)
Params.Add(NewParam)
End Sub
'ERROR CHECKING
Public Function HasException(Optional Report As Boolean = False) As Boolean
If String.IsNullOrEmpty(Exception) Then Return False
If Report = True Then MsgBox(Exception, MsgBoxStyle.Critical, "Exception:")
Return True
End Function
End Class
SQLControl class is the brain child of VBToolbox user. It is a good tool, once created, just simply use it and not have to worry about all complicated setups that normally associated with SQL data connection. Besides, it makes the solution much cleaner & simpler.
There is no need to modify SQLControl class, when you need to update the changes, simply:
'SAVE UPDATES TO DATABASE
SQL.DBDA.UpdateCommand = New SqlClient.SqlCommandBuilder(SQL.DBDA).GetUpdateCommand 'Need primary key in SEL statement
SQL.DBDA.Update(SQL.DBDT)
and refresh the DataGridview afterwards.
The issue appears to be as I suspected it was. Here's for code from the form:
SQL.ExecQuery("SELECT * FROM dtbRateVerse;")
SQL.DBDA.UpdateCommand = New SqlClient.SqlCommandBuilder(SQL.DBDA).GetUpdateCommand
SQL.DBDA.Update(SQL.DBDT)
In that, you first call ExeQuery and finally call Update on the data adapter and pass the DBDT DataTable. In your ExecQuery method, you have this:
DBDT = New DataTable
DBDA = New SqlDataAdapter(DBCmd)
RecordCount = DBDA.Fill(DBDT)
That means that the first code snippet is going to be calling Update and passing a DataTable that was just freshly created and populated. Why would you expect that DataTable to have any changes in it to save? This is an example of why I think DAL classes like this are garbage.
If you're going to be using a class like that then you should be creating a command builder inside it when you create the data adapter, e.g.
'DB DATA
Public DBDA As SqlDataAdapter
Public DBCB As SqlCommandBuilder
Public DBDT As DataTable
and:
'EXECUTE COMMAND & FILL DATASET
DBDT = New DataTable
DBDA = New SqlDataAdapter(DBCmd)
DBCB = New SqlCommandBuilder(DBDA)
RecordCount = DBDA.Fill(DBDT)
Now there's no need to call ExecQuery again or create your own command builder. Just call ExecQuery once when you want the data, get the populated DataTable, use it and then call Update on the data adapter and pass that DataTable when it's time to save.
That said, you don't even necessarily need to change that class. If you already have an instance and you already called ExecQuery then it already contains the data adapter and the DataTable. You can still create your own command builder if you want but just don't call ExecQuery again and lose the objects you already had. If you changed that first code snippet to this:
Dim commandBuilder As New SqlClient.SqlCommandBuilder(SQL.DBDA)
SQL.DBDA.Update(SQL.DBDT)
Then it would work, assuming that you are using the same SQLControl instance as you used to get the data in the first place.

Database not updating new row

Insert new row inside DataGridView
This answer makes it seem like the database should update with the rows.add
Some other sites have instructions, but form a perspective of creating the database from scratch. I already have a database and just want the stupid thing to accept new data.
Here's what I have done:
Private Sub InitializeDataGridView()
Try
' Set up the DataGridView.
With Me.DataGridView1
' Automatically generate the DataGridView columns.
.AutoGenerateColumns = True
' Set up the data source.
'bindingSource1.DataSource = GetData("SELECT * FROM Places and Stuff")
MyTable = GetData("SELECT * FROM Places and Stuff")
'MyDataSet = bindingSource1.DataSource
'MyTable = MyDataSet.Tables(0)
.DataSource = MyTable
' Automatically resize the visible rows.
.AutoSizeRowsMode = DataGridViewAutoSizeRowsMode.DisplayedCellsExceptHeaders
' Set the DataGridView control's border.
.BorderStyle = BorderStyle.Fixed3D
' Put the cells in edit mode when user enters them.
.EditMode = DataGridViewEditMode.EditOnEnter
' Disables Add New Row
.AllowUserToAddRows = False
End With
Catch ex As SqlException
MessageBox.Show(ex.ToString, _
"ERROR", MessageBoxButtons.OK, MessageBoxIcon.Exclamation)
System.Threading.Thread.CurrentThread.Abort()
End Try
End Sub
I am binding the DGV to a table. It seems like maybe I need a dataset somewhere to update but I cannot figure out how to populate a dataset with a table that is also a sql database. You can also see where I have played around with other datasets/datatables etc.
I also got my datagridview to add a row but the database is being lazy:
Private Sub btnAdd_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnAdd.Click
'Determine Last Row Index
Dim dgvrowCnt As Integer = DataGridView1.Rows.Count - 1
If DataGridView1.Rows.Count > 0 Then
Dim myRow As DataRow = MyTable.NewRow
myRow(0) = DataGridView1.Rows(dgvrowCnt).Cells(0).Value + 1
MyTable.Rows.Add(myRow)
Else
Dim myRow As DataRow = MyTable.NewRow
myRow(0) = 230
MyTable.Rows.Add(myRow)
End If
End Sub
I am a little saddened by not being able to use myRow("<column name here>") = 230 but I'll have to get over it I guess.
I have tried refreshing and checking the table to see if my form needs to be refreshed, but that doesn't seem to be the case.
This page http://support.microsoft.com/kb/301248 has 2 lines and claims it does what I am hoping for:
Dim objCommandBuilder As New SwlCammandBuilder(daAuthors)
daAuthors.Update(dsPubs, "Authors")
I cannot get my table into a dataset as shown in the binding lines of my example.
It seems that you haven't understood a fundamental concept of ADO.NET. The DataTable and other objects like the DataSet are 'disconnected' objects, meaning that adding/updating and removing rows doesn't update/insert/delete the database table.
You need to create an SqlCommand, prepare its command text and then Execute a query to update your db (other methods include using an SqlDataAdapter and its Update method)
For example, to insert a single row in a datatable your code should be something like this
Using con = New SqlConnection(.....constringhere...)
Using cmd = new SqlCommand("INSERT INTO table1 (field1) values (#valueForField)", con)
con.Open()
cmd.Parameters.AddWithValue("#valueForField", newValue)
cmd.ExecuteNonQuery()
End Using
End Using
A more complete tutorial could be found here
Instead this could be a pseudocode to use a SqlDataAdapter and a SqlCommandBuilder to automate the construction of the commands required to store your changes back to the database
' Keep the dataset and the adapter at the global class level'
Dim da As SqlDataAdapter = Nothing
Dim ds As DataSet
Private Function GetData(ByVal sqlCommand As String) As DataSet
ds As New DataSet()
Dim connectionString As String = "Data Source=...."
Using con = New SqlConnection(connectionString)
conn.Open()
Using command = New SqlCommand(sqlCommand, con)
Using da = New SqlDataAdapter(command)
da.Fill(ds)
End Using
End Using
End Using
Return ds
End Function
Use the first table inside the DataSet returned by GetData as Datasource of the grid (or just use the whole dataset)
.DataSource = GetData(.......).Tables(0)
' Add a new button to submit changes back to the database'
Private Sub btnSave_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnAdd.Click
Dim builder = New SqlCommandBuilder(da)
da.UpdateCommand = builder.GetUpdateCommand()
da.InsertCommand = builder.GetInsertCommand()
da.DeleteCommand = builder.GetDeleteCommand()
da.Update(ds)
End Sub
Please, note that I cannot test this code, and I offer it as a pseudocode without any error checking required by a more robust application.

populate sqldata base table contents into dropdownlist

What is the problem in below code. I don't know how to add sqldatabase table content into dropdownlist please help
Protected Sub DropDownList3_SelectedIndexChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles DropDownList3.SelectedIndexChanged
Dim sqlcon As New SqlConnection("Data Source=SOf-22\SQLEXPRESS;Initial Catalog=Sales_oct_3;Persist Security Info=True;User ID=s;Password=121")
If sqlcon.State = ConnectionState.Open Then
sqlcon.Close()
End If
sqlcon.Open()
Dim strcommand As String
strcommand = "select item from tgnitem"
Dim sqlcomm As New SqlCommand(strcommand, sqlcon)
Dim o As String = sqlcomm.ExecuteNonQuery()
End Sub
End Class
You are doing many wrong things here. For things as simple as this, you should better stick to strongly typed DataSets. They'll lift a lot of burden from you. You'll not need to maintain connections, manually execute queries, traverse through results and fill them into your UI controls etc. Learn more about typed DataSets and simple binding scenarios (such as yours) and they'll give you long-term benefits.
A simple 4 step mechansim for this kind of stuff when using typed DataSets is:
Add a new DataSet to your project.
Add a new TableAdapter by right-clicking in the DataSet designer surface. Write your query and it will create a type DataTable for you. You could even drag a table using Server Explorer.
Add an instance of your type DataSet onto your form.
Set DataSource property of your ComboBox to this instance and DataMember to the name of your DataTable. Set DisplayMember and ValueMember to the display and value fields of your DataTable, e.g. DisplayMember = "Name" and ValueMember = "ItemID".
see this might helpful to you
Public Shared Function ClientList() As DataTable
Dim dtResult As DataTable = Nothing
Try
Dim objDataLayer As New ClsDataLayer()
objDataLayer.AddParameter("#REF_USER_ID", ClsCommons.IntUserId)
dtResult = objDataLayer.ExecuteDataTable("TR_PROC_GetClientList")
Catch ex As Exception
MsgBox(ex.Message)
End Try
Return dtResult
End Function
Public Shared Sub ClientList(ByVal cmbClientList As ComboBox)
cmbClientList.DropDownStyle = ComboBoxStyle.DropDownList
Try
Dim dtClientList As DataTable = ClsClientManager.ClientList()
If ((Not IsNothing(dtClientList)) AndAlso dtClientList.Rows.Count > 0) Then
Dim drClient As DataRow = dtClientList.NewRow()
drClient(0) = -1
drClient(1) = "< -- Select Department -- >"
dtClientList.Rows.InsertAt(drClient, 0)
cmbClientList.DataSource = dtClientList
cmbClientList.DisplayMember = "CLIENT_NAME"
cmbClientList.ValueMember = "CLIENT_ID"
Else
MessageBox.Show("There is no Department to load", "Talent Recruit", MessageBoxButtons.OK, MessageBoxIcon.Information)
End If
Catch ex As Exception
MsgBox(ex.Message)
End Try
End Sub

how to populate items from database in a listbox in vb.net

I was developing an application using oop concept.I have a class that has 2 attributes and have Get and Set methods namely WorkItemNumber and Description.
On the client side i have a list box used to populate the work items based on their description.Here's the code i wrote in the class o read items from the database.
Public Sub LoadWorkItem()
' Load the data.
' Select records.
Dim oWorkItem As WorkItem = New WorkItem()
Dim conn As New OleDbConnection
Dim data_reader As OleDbDataReader
conn = oWorkItem.GetDbConnection()
Dim cmd As New OleDbCommand("SELECT * FROM work_item ORDER BY [work item number]", conn)
data_reader = cmd.ExecuteReader()
'ListBox1.Items.Clear()
If data_reader.HasRows = True Then
Do While data_reader.Read()
WorkItemNumber = data_reader.Item("work item number")
Description = data_reader.Item("description")
Loop
End If
data_reader.Close()
data_reader = Nothing
cmd.Dispose()
cmd = Nothing
conn.Close()
conn.Dispose()
End Sub
How do i populate the listbox using the code,and if there's any improvement on the code please do tell me as well.Thank you
To poulate your ListBox, do this...
ListBox1.Item.Clear()
If data_reader.HasRows Then
Do While data_reader.Read()
WorkItemNumber = data_reader.Item("work item number")
Description = data_reader.Item("description")
ListBox1.Items.Add(New ListItem(Description, WorkItemNumber)
Loop
End If
As far as improvements, start by using a Using statement for the DB connection. In your code, if there is an exception while the database connection is open, it will never get closed. This is better...
Using conn As OleDbConnection = oWorkItem.GetDbConnection()
' Execute SQL and populate list...
End Using
The above code assures that your connection will be closed.
Then, turn on Option Strict and Option Explicit. This will force you to declare the Type for Description and WorkItemNumber and cast them as Strings when adding a ListItem. This will reduce run-time errors.
Finally, if this is anything but a small app you are doing as a learning experiment, you should read up on tiered application design. Your code is mixing UI, business logic, and data access in the same method. This is generally frowned upon.
Your "user interface" LoadWorkItem() method should ask a "core" method for a list of WorkItems.
Your core method should then ask a "data access" method for data.
The "data access" method should make the call to the database.
Happy coding.
Update: You can find excellent info about n-Tier architecture on MSDN. A good book to read once you grasp the fundamentals and have some confidence in .NET is Visual Basic .NET Business Objects.
Imports System.Data.SqlClient 'Reference The Sql Client
Public Class Form1
''Make sure to change the connection string below to your connection string this code only works for SQL DataBase. If Your connection String is wrong This will Not Work
Dim connString As String = "Data
Source=NameofYourSQLServer\SQLEXPRESS;Initial Catalog=NameOfYourDataBase;Integrated Security=True"
Dim tblDIV As DataTable
Dim daDIV As SqlDataAdapter
Dim dsDIV As New DataSet
Dim oCon As SqlConnection
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Dim oCon = New SqlConnection
oCon.ConnectionString = connString
dsDIV = New DataSet
' Select all Fields and order by ID or Replace * with name of Field
daDIV = New SqlDataAdapter("SELECT * FROM NameOfYourTable ORDER BY Id DESC", oCon)
'*** Define command builder to generate the necessary SQL
Dim builder As SqlCommandBuilder = New SqlCommandBuilder(daDIV)
builder.QuotePrefix = "["
builder.QuoteSuffix = "]"
Try
daDIV.FillSchema(dsDIV, SchemaType.Source, "DIV")
daDIV.Fill(dsDIV, "DIV")
tblDIV = dsDIV.Tables("DIV")
ListBox1.DataSource = tblDIV
ListBox1.DisplayMember = "NameOfTheFieldYouWanttoDisplay"
Catch ex As Exception
MsgBox("Encountered an Error;" & vbNewLine & ex.Message)
oCon.Close()
End Try
End Sub