Updating database with BindingSource data - vb.net

This is my first post in here, but this forum already helped me a lot.
First, sorry for my English, i'm from Brazil and i'm trying to write without a translator.
I'm developing a software for a supermarket, but i'm having problems with the connection to the database. I'm trying to make all the connections and transactions programmatically (DataSets, BindingSources and so).
I've already managed to connect with SQL Server Express 2008, using a Function ("consulta") inside a Module ("db"):
Dim ad As SqlDataAdapter = New SqlDataAdapter
Function consulta(ByVal tabela As String, Optional opt As Boolean = False, Optional optparam As String = "") As DataSet
Dim ds As New DataSet
Try
Dim connstring As String = "Data Source=NOTEBOOK\SQLEXPRESS;Initial Catalog=SysMarket;Persist Security Info=True;User ID=admin;Password=XXXXXX"
Dim conObj As New SqlConnection(connstring)
Dim sql As String
If opt = True Then
sql = "SELECT * FROM " & tabela & " " & optparam
Else
sql = "SELECT * FROM " & tabela
End If
Dim cmd As SqlCommand = New SqlCommand(sql, conObj)
ad.SelectCommand = cmd
conObj.Open()
ad.Fill(ds, tabela)
ad.Dispose()
cmd.Dispose()
conObj.Close()
Return ds
Catch ex As Exception
MessageBox.Show("Erro na consulta" & vbCrLf & ex.InnerException.ToString, "Erro", MessageBoxButtons.OK, MessageBoxIcon.Error)
ds.Clear()
Return ds
End Try
End Function
And this is a part of the main code where I make a SelectQuery and put into a BindingSource:
Dim ds As DataSet = db.consulta("departamentos")
Private Sub cad_departamento_Load(sender As Object, e As EventArgs) Handles MyBase.Load
BindingSource1.DataSource = ds
BindingSource1.DataMember = "departamentos"
TextBox1.DataBindings.Add("Text", BindingSource1, "id")
TextBox2.DataBindings.Add("Text", BindingSource1, "departamento")
End Sub
But my problem is when I have to Update the database, by adding, editing or deleting some item from BindingSource. Because in the Module I've closed the connection to the SQL Server. So I will need reopen this connection and then, somehow "read" the DataSet with the change and Update the database?
Someone could explain this to me or show me a example?
Thank you.

You will use a data adapter to save the data, just as you used one to retrieve the data. You will have to create an InsertCommand if you want to insert new records, an UpdateCommand if you want to update existing records and a DeleteCommand if you want to delete existing records. You can write those yourself or, if the conditions are right, you can use a command builder to do it for you.
If your query is based on a single table and you want to insert/update all the columns you retrieve back to that same table then a SqlCommandBuilder may be your best bet. You simply pass in the query and the command builder will use it to generate the action commands. That gives you limited flexibility but if you're just doing single-table operations then you don't need that added flexibility.
Such a method might look something like this:
Public Sub SaveChanges(tableName As String, data As DataSet)
Dim query = "SELECT * FROM " & tableName
Using adapter As New SqlDataAdapter(query, "connection string here")
Dim builder As New SqlCommandBuilder(adapter)
adapter.Update(data, tableName)
End Using
End Sub

I did what you said, but when I open the Form again, the new data are not there.
I made some changes in the code, perhaps because it did not work
Private Sub btnSave_Click(sender As Object, e As EventArgs) Handles btnSave.Click
BindingSource1.EndEdit()
ds.AcceptChanges()
db.SaveChanges("departamentos", "INSERT INTO departamentos VALUES('', " & TextBox2.Text & ")", ds)
ds = db.consulta("departamentos")
End Sub
And the code in the Module
Function SaveChanges(tableName As String, query As String, data As DataSet)
Using adapter As New SqlDataAdapter(query, "Data Source=NOTEBOOK\SQLEXPRESS;Initial Catalog=SysMarket;Persist Security Info=True;User ID=admin;Password=XXXXX")
Dim builder As New SqlCommandBuilder(adapter)
adapter.Update(data, tableName)
Return True
End Using
End Function

Related

How to delete a row in sql using vb.net

Sorry if its easy or basic i am brand new to sql and tables so im just trying to figure it out
Basically im trying to delete a row that the user selects
By having them click on a row then clicking a delete button but i don't know how that should look ive tried a few different ways but none of them seem to work.
No error comes up but it just dosen't delete the row
Private Sub DeleteSelectedUsers()
Dim connection As SqlConnection = New SqlConnection()
connection.ConnectionString = "Data Source=GERARD-PC\SQLEXPRESS; Initial Catalog=TestDB;User ID=AccountsUser;Password=password123"
connection.Open()
Dim adp As SqlDataAdapter = New SqlDataAdapter _
("Delete * from dgrdUsers.SelectedRows(0).Cells", connection)
End Sub
Private Sub btnDelete_Click(sender As Object, e As EventArgs) Handles btnDelete.Click
Try
Dim username As String = dgrdUsers.SelectedRows(0).Cells.Item("Username").Value.ToString()
If (MessageBox.Show(Me, "Do you want to delete user " & username & "?", "Confirm Delete", MessageBoxButtons.YesNo, MessageBoxIcon.Question) = DialogResult.Yes) Then
DeleteSelectedUsers()
End If
Catch ex As Exception
End Try
End Sub
Any ideas?
The syntax required to delete a row in the database table requires at least three parts.
The DELETE command
The FROM statement to identify the table where the delete action should occur
The WHERE condition to identify the record (or records) to delete
So it is a string like this: DELETE FROM tablename WHERE condition
and applied to your code you get this.
Private Sub DeleteSelectedUsers(userName as String)
Using connection As SqlConnection = New SqlConnection()
connection.ConnectionString = "...."
connection.Open()
Dim cmd As SqlCommand = New SqlCommand _
("DELETE FROM Table WHERE userName = #user", connection)
cmd.Parameters.Add("#user", SqlDbType.NVarChar).Value = userName
cmd.ExecuteNonQuery()
End Using
End Sub
(Table and UserName are fantasy names because we don't know what is the actual schema of your database)
Other things I have changed:
The connection is created inside a using block to be sure a proper
closure and dispose happens even in case of errors
The name of the user to remove should be passed as parameter to the
function
No need to use an adapter when you just need to execute a single
SqlCommand
The query doesn't concatenate strings to build the command but use a
parameter added to the command itself and specifying a type for the
data matching the type on the database table

Trying to delete a record from my access database in visual basic studio 2010

Private Function CreatePlayerAdapter(ByVal playerDBconnection As OleDbConnection) As OleDbDataAdapter
// Initiating instances for the function
Dim dataAdapter As OleDbDataAdapter = New OleDbDataAdapter()
Dim myCommand As OleDbCommand
Dim parameter As OleDbParameter
// establishing the string to tell where to delete record from and how to find the record i want.
// PlayerIDTextBox.Text is a text on a form that is populated from the database after selecting a list of name (this works correctly) // connection is already open and is directed to correct place
Dim sql As String = "DELETE * FROM Players WHERE ID ='" & CInt(PlayerIDTextBox.Text) & "'"
myCommand = New OleDbCommand(sql, playerDBconnection)
parameter = myCommand.Parameters.Add("ID", OleDbType.Char, 3, "ID")
parameter.SourceVersion = DataRowVersion.Original
dataAdapter.DeleteCommand = myCommand
Return dataAdapter
End Function
// i call this function after executing a button click.
//ListPlayerComboBox.Text is populated with the names and needs it a name to fill PlayerIDTextBox.Text(works correctly)
Private Sub RemovePlayerButton_Click(sender As System.Object, e As System.EventArgs) Handles RemovePlayerButton.Click
If ListPlayerComboBox.Text = " " Then
MsgBox("Please Select a Player.")
Else
Me.CreatePlayerAdapter(playerDBConnection)
End If
End Sub
// no errors occur. However, nothing is done in the database. help please?
Notes:
1)Never leave your OleDbConnection Open. Only allow it to be opened when you actually need it. This will save you from a lot of headaches later on. The reasons why can be found on following stackoverflow question.
2) There is no reason to return an OleDbDataAdapter if you don't intend on using it.
3) Use your parameters correctly : see below example2
4) Keep in mind that there are some restricted keywords in Access. Luckely for you ID isn't one. The restrictedKeywords can be found here: Keywords
I'm probably missing some further points here. Anyone should be free to add em.
Why not adjust your Function CreatePlayerAdapter to the following:
1) Without parameters
Private Sub CreatePlayerAdapter(ByVal playerDBconnection As OleDbConnection)
Dim myCommand As OleDbCommand
Dim sql As String = "DELETE * FROM Players WHERE ID =" & CInt(PlayerIDTextBox.Text)
myCommand = New OleDbCommand(sql, playerDBconnection)
playerDBconnection.Open()
myCommand.ExecuteNonQuery()
playerDBconnection.Close()
End Sub
2) With parameters
Private Sub CreatePlayerAdapter(ByVal playerDBconnection As OleDbConnection)
Dim myCommand As OleDbCommand
Dim sql As String = "DELETE * FROM Players WHERE ID = #playerId"
myCommand = New OleDbCommand(sql, playerDBconnection)
Dim param As New OleDb.OleDbParameter(#playerId", CInt(PlayerIDTextBox.Text))
myCommand.Add(param)
playerDBconnection.Open()
myCommand.ExecuteNonQuery()
playerDBconnection.Close()
End Sub
The method ExecuteNonQuery executes the query passed to the command on the specified OleDbConnection and returns the number of rows affected. More info Here

Data binding to Textboxes

Dim myconn As New SqlConnection("Server=server,Trusted_Connection=True,Database=database")
'selects from mt table linking the current pc to a row
Dim sql As String = "SELECT * from idset " & vbcrlf &
"Where pcname= '" & pcname & "'"
Dim ds As New DataSet
Dim da As New SqlDataAdapter(sql, myconn)
da.Fill(ds, "Setup")
txtClientID.DataBindings.Add("text", ds.Tables("idset"), "CLID")
I don't know why its not working for some reason its not filling the data set did I declare something wrong?
The reason why it don't work is because you specify that the incoming table should be mapped to a table named Setup. Your data set doesn't contain a table named Setup, so the incoming table will be named... well, Setup.
Try this instead:
da.Fill(ds, "idset")
Also, I strongly suggest you:
Set option strict on
Always use parameterized/prepared SQL queries.
Always use the Using statement when working with disposable objects.
Seriously.
The best way to debug bindings is to use a BindingSource and handle the BindingComplete event.
Private bs As BindingSource
Private ds As DataSet
Private Sub Initialize(pcname As String)
Me.ds = New DataSet()
Using connection As New SqlConnection("Server=server,Trusted_Connection=True,Database=database")
connection.Open()
Using command As New SqlCommand()
command.Connection = connection
command.CommandText = "SELECT * from [idset] Where [pcname] = #pcname;"
command.Parameters.AddWithValue("#pcname", pcname)
Using adapter As New SqlDataAdapter(command)
adapter.Fill(Me.ds, "idset")
End Using
End Using
End Using
Me.bs = New BindingSource(Me.ds, "idset")
AddHandler bs.BindingComplete, AddressOf Me.HandleBindingCompleted
Me.txtClientID.DataBindings.Add("Text", Me.bs, "CLID")
End Sub
Private Sub HandleBindingCompleted(sender As Object, e As BindingCompleteEventArgs)
If (Not e.Exception Is Nothing) Then
Debug.WriteLine(e.ErrorText)
End If
End Sub

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.

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