vb.net and using SQLite - vb.net

I just want to make sure that this is the right code for working with SQLite for fastest performance..
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim cons As New SQLite.SQLiteConnection
cons.ConnectionString = "Data Source=C:\database.s3db; Version=3"
cons.Open()
Using tx = cons.BeginTransaction()
Dim cmd As SQLite.SQLiteCommand
cmd = cons.CreateCommand()
For i As Integer = 0 To 1000
Try
cmd.CommandText = "INSERT INTO table1 VALUES('" & i & "')"
cmd.ExecuteNonQuery()
Catch ex As Exception
End Try
Next
tx.Commit()
cmd.Dispose()
End Using
cons.Close()
End Sub

As I mentioned, proper way of doing this using parameterized queries, not swallowing the exception, and using statements wherever necessary would look something like this.
Do note this is not the fastest way of doing.
Private Sub InsertRows()
Using conn As New SqlConnection
conn.Open()
Using tx = conn.BeginTransaction()
For i As Integer = 0 To 1000
Using cmd = conn.CreateCommand() 'Proper using statements wherever necessary
Try
cmd.CommandText = "INSERT INTO table1 VALUES(#ColumnName)" 'Paramertized queries
cmd.Parameters.AddWithValue("#ColumnName", i)
cmd.ExecuteNonQuery()
Catch ex As Exception
logger.ErrorException(ex) 'Logging the exception or shoe messagebox
End Try
End Using
Next
End Using
End Using
End Sub
Ideally you shouldn't continue execution if there is an exception in a tight loop doing same task. If one fails there is a chance that everything can fail. So in that case you should remove the try/catch inside the loop and wrap it over the for loop.

Related

"No value given for one or more required parameters" error using OleDbCommand

I am trying to update a record in MS Access using VB.net. This code will be under the "Delivered" button. When I try to run it, it shows the "No value given for one or more required parameters" error. Here is my code:
Private Const strConn As String = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=C:\Users\Traicy\Downloads\MWL(11-30-2021)\MadeWithLove\MadeWithLove\MadeWithLove.mdb;"
ReadOnly conn As OleDbConnection = New OleDbConnection(strConn)
Dim cmd As OleDbCommand
Public Sub DeliveredUpdate()
Const SQL As String = "UPDATE DELIVERY SET delivery_status = #status"
cmd = New OleDbCommand(SQL, conn)
' Update parameter
cmd.Parameters.AddWithValue("#status", "Delivered")
' Open connection, update, then close connection
Try
conn.Open()
If cmd.ExecuteNonQuery() > 0 Then
MsgBox("The delivery status was successfully updated.")
End If
conn.Close()
Catch ex As Exception
MsgBox(ex.Message)
conn.Close()
End Try
End Sub
Do not declare connections or commands outside of the method where they are used. These database objects use unmanaged resources. They release these resources in their Dispose methods. The language provides Using blocks to handle this.
As mentioned in comments by Andrew Morton, you should have a Where clause to tell the database which record to update. This would contain the primary key of the record. I guessed at a name for the field, OrderID. Check your database for the real field name.
Access does not use named parameters but you can use names for readability. Access will be able to recognize the parameters as long as they are added to the Parameters collection in the same order that they appear in the sql string. In some databases the Add method is superior to AddWithValue because it doesn't leave the datatype to chance.
It is a good idea to separate your database code from your user interface code. If you want to show a message box in your Catch put the Try blocks in the UI code. This way your function can be used in a web app or mobile app without rewriting.
Public Function DeliveredUpdate(ID As Integer) As Integer
Dim recordsUpdated As Integer
Dim SQL As String = "UPDATE DELIVERY SET delivery_status = #status Where OrderID = #Id;"
Using conn As New OleDbConnection(strConn),
cmd As New OleDbCommand(SQL, conn)
cmd.Parameters.Add("#status", OleDbType.VarChar).Value = "Delivered"
cmd.Parameters.Add("#Id", OleDbType.Integer).Value = ID
conn.Open()
recordsUpdated = cmd.ExecuteNonQuery
End Using 'closes and disposes the command and connection
Return recordsUpdated
End Function
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim retVal As Integer
Dim id As Integer = 1 'not sure where you are getting this value from
Try
retVal = DeliveredUpdate(id)
Catch ex As Exception
MsgBox(ex.Message)
End Try
If retVal > 0 Then
MsgBox("The delivery status was successfully updated.")
End If
End Sub

error regular comes Invalid SQL statement; expected 'DELETE', 'INSERT', 'PROCEDURE', 'SELECT', or 'UPDATE'

Private Sub ComboBox1_SelectedIndexChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ComboBox1.SelectedIndexChanged, MyBase.Activated
con.Close()
con.Open()
str = "select * from customer where CustomerID='" & ComboBox1.Text & "'"
cmd = New OleDbCommand(str, con)
da.SelectCommand = cmd
If IsNumeric(ComboBox1.Text) Then
cmd.CommandText = str = "select * from customer where CustomerID=#cid"
cmd.Prepare()
cmd.Parameters.AddWithValue("cid", ComboBox1.Text)
Dim dr As OleDbDataReader = cmd.ExecuteReader()
Try
If dr.Read() Then
TextBox1.Text = dr.GetValue(1)
TextBox2.Text = dr.GetValue(2)
TextBox3.Text = dr.GetValue(3)
TextBox4.Text = dr.GetValue(4)
TextBox5.Text = dr.GetValue(5)
dr.Close()
End If
Catch ex As Exception
MsgBox("", ex.Message)
dr.Close()
Finally
con.Close()
End Try
End If
Your code has several issues.
You did not provide your complete Combobox1_SelectedIndexChanged method. At least the last line that ends the method is missing.
You are reusing a connection. It is better practice to create a new connection (and dispose it afterwards) each time you need it. (Connection pooling might already reuse connections in the background.)
You have an exception handling mechanism that doesn't cover all your logic that can throw exceptions.
You are using two approaches to pass the SQL command text to the command object. One approach should suffice.
You call the Prepare method before you add your parameters to the command object. Apart from the fact that calling Prepare probably is not explicitly needed, I guess it should be called after you have added your parameters to the command object.
You are using the AddWithValue method to add parameters to your command object. That is evil.
Private Sub ComboBox1_SelectedIndexChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ComboBox1.SelectedIndexChanged, MyBase.Activated
'Better to use explicit column names instead of * here, especially if you use `GetValue` with a numeric index when mapping the query results to your textboxes.
Dim str As String = "select * from customer where CustomerID=#cid"
Try
Using con As New OleDbConnection("<connection string here>"), cmd As New OleDbCommand(str, con)
con.Open()
'Assuming here that CustomerID in the customer table is of type integer
cmd.Parameters.Add("#cid", OleDbType.Integer).Value = Integer.Parse(ComboBox1.Text)
Using dr As OleDbDataReader = cmd.ExecuteReader()
If dr.Read() Then
'Instead of using magical (ordinal) numbers, it would be better to use GetOrdinal as well: dr.GetValue(dr.GetOrdinal("fieldName"))
TextBox1.Text = dr.GetValue(1)
TextBox2.Text = dr.GetValue(2)
TextBox3.Text = dr.GetValue(3)
TextBox4.Text = dr.GetValue(4)
TextBox5.Text = dr.GetValue(5)
End If
'Perhaps you also want to include an Else block (in which case the database query did not return any results) to clear the textboxes?
End Using
End Using
Catch ex As Exception
MsgBox("", ex.Message)
'Closing any ADO.NET objects will be done automatically when they are disposed (when the Using block goes out of scope).
End Try
End Sub
Obviously, I have not tested the code above, since I do not have a fitting test environment for it. Please let me know if this code causes any issues you cannot solve yourself.
You have two Sql statements in your code.
1:
str = "select * from customer where CustomerID='" & ComboBox1.Text & "'"
2:
cmd.CommandText = str = "select * from customer where CustomerID=#cid"
You should get rid of #1 - delete that line of code and change #2 to be:
cmd.CommandText = "select * from customer where CustomerID=#cid"

how to display data in text box in vb.net using sql

Private Sub BtnReturn_Click(sender As Object, e As EventArgs) Handles btnReturn.Click
If BorrowAccession.Text = "" Or txtBorrowerstype.Text = "" Then
MsgBox("All fields are required.", MsgBoxStyle.Exclamation)
ElseIf txtremarks.Text = "Over Due" Then
sql = "Select * From `maintenance` fine ='" & txtfine.Text & "' "
reloadtxt(sql)
End sub
how will i display the fine in txtfine.text from my maintenance database after it satisfy the condition from txtremarks. i tried some youtube tutorials but only displaying it from data grid .. want i basically want is directly display it from database to textbox. btw im newbie in vb programming thank you in advance
for my reloadtxt this is the code.
Public Sub reloadtxt(ByVal sql As String)
Try
con.Open()
With cmd
.Connection = con
.CommandText = sql
End With
dt = New DataTable
da = New MySqlDataAdapter(sql, con)
da.Fill(dt)
Catch ex As Exception
' MsgBox(ex.Message & "reloadtxt")
Finally
con.Close()
da.Dispose()
End Try
End Sub
To populate an object with data from a database you need to access the objects text property.
Textbox1.Text = "Some Text, static or dynamic"
Since you are pulling the data from a datatable you would access the column named "fine" and put that value in the textbox.text property.
Textbox1.Text = dt.row(0).item("fine").tostring
Changed Or to OrElse because it short circuits the If and doesn't have to check the second condition if the first condition is True.
In the reloadtxt method you filled a DataTable and did nothing with it. I changed it to a Function that returns the DataTable. The connection and command are now included in a Using...End Using block so they are closed and disposed even if there is an error.
Never concatenate strings to build an sql statement. Always used parameters.
Private Sub BtnReturn_Click(sender As Object, e As EventArgs) Handles btnReturn.Click
If BorrowAccession.Text = "" OrElse txtBorrowerstype.Text = "" Then
MsgBox("All fields are required.", MsgBoxStyle.Exclamation)
ElseIf txtremarks.Text = "Over Due" Then
Dim dt = reloadtxt()
DataGridView1.DataSource = dt
End If
End Sub
Public Function reloadtxt() As DataTable
Dim dt As New DataTable
Using con As New MySqlConnection("Your connection string"),
cmd As New MySqlCommand("Select * From maintenance Where fine = #Fine", con)
cmd.Parameters.Add(#Fine, MySqlDbType.VarChar, 50).Value = txtfine.Text
Try
con.Open()
dt.Load(cmd.ExecuteReader)
Catch ex As Exception
MsgBox(ex.Message & "reloadtxt")
End Try
End Using
Return dt
End Function

Error: "There is already an open DataReader associated with this Connection which must be closed first"

i get this error message, this is my code, please help me
Private Sub txtceknofak_Leave(sender As Object, e As EventArgs) Handles txtceknofak.Leave
Dim nf As String
nf = "select no_fak from terima_cucian where no_fak = '" & txtceknofak.Text & "'"
comm = New SqlCommand(nf, conn)
rdr = comm.ExecuteReader()
If rdr.HasRows Then
btproses.Enabled = True
btproses.Focus()
Else
MsgBox("Nomor faktur tidak ada")
txtceknofak.Clear()
txtceknofak.Focus()
End If
rdr.Close()
End Sub
Since the connection is not part of the method it seems to be a field in your class. I would discourage from that. Instead use a local variable and open/close it when you need it. Actually the connection-pool will not really open/close the physical connection, so you don't need to be afraid that this is inefficient.
You can ensure that the connection gets closed even on error by using Try-Finally or -more readable and concise- with the Using-statement:
Private Sub txtceknofak_Leave(sender As Object, e As EventArgs) Handles txtceknofak.Leave
Dim nf As String = "select no_fak from terima_cucian where no_fak = #no_fak"
Using conn = New SqlConnection(connectionstring)
Using comm = New SqlCommand(nf, conn)
comm.Parameters.AddWithValue("#no_fak", txtceknofak.Text)
conn.Open()
Using rdr = comm.ExecuteReader()
If rdr.HasRows Then
btproses.Enabled = True
btproses.Focus()
Else
MsgBox("Nomor faktur tidak ada")
txtceknofak.Clear()
txtceknofak.Focus()
End If
End Using
End Using
End Using ' *** this will also close the connection *** '
End Sub
I have also used sql-parameters to prevent sql-injection.
make new instance of the reader
rdr = new comm.ExecuteReader();
Thanks

vb.net polling Sql server once a second causing timeout

I was asked to do a system that would poll one table in the database every second and if it counters a row that meets a criteria start actions to handle that.
I've done this but every now and then I get a time out exception. I have a WPF application where I have a thread that runs in background. This thread has a loop and sleeps for one second at the end of the loop. The connection to the database is opened inside "using" clause.
Below is my thread sub:
Private Sub PollDatabase()
While m_StopThread = False
Try
Dim listOfRows As List(Of DataObject) = db.GetDataObjects()
... Do something with the rows ...
Catch ex As Exception
m_log.WriteLine(ex.ToString())
End Try
Thread.Sleep(1000)
End While
End Sub
And my SQL function looks like this:
Public Function GetDataObjects() As List(Of DataObject)
Dim result As New List(Of DataObject)
Dim sb As New StringBuilder("... the sql query ...")
Using cnn = New SqlConnection(_connectionString)
cnn.Open()
Using cmd = New SqlCommand(sb.ToString(), cnn)
cmd.CommandTimeout = 0
Using DataReader As SqlDataReader = cmd.ExecuteReader()
Do While DataReader.Read()
... read the columns from table
to the dataobject ...
result.Add(DataObject)
Loop
End Using
End Using
End Using
Return result
End Function
Now what seems randomly my log has a time out exception:
System.Data.SqlClient.SqlException (0x80131904): Timeout expired. The timeout period elapsed prior to completion of the operation or the server is not responding.
...
at System.Data.SqlClient.SqlConnection.Open()
My questions are: is this at all save way of doing this? Or am I doing something fundamentally wrong here? And of course if anyone have a suggestion to fix this issue.
EDIT:
I tried a bit different approach with the SQL function. I'm now opening a connection once when my application starts and dumped the "using" clauses. So my function looks something like this now:
Public Function GetDataObjects() As List(Of DataObject)
Dim result As New List(Of DataObject)
Dim sb As New StringBuilder("... the sql query ...")
_sqlCmd.CommandText = sb.ToString()
Using DataReader As SqlDataReader = _sqlCmd.ExecuteReader()
Do While DataReader.Read()
... fill the list with objects ...
Loop
End Using
Return result
End Function
My log is clean form errors. So is there something wrong opening a connection to the server once in a second as I do with the using?
EDIT:
I've done a lot of testing now to identify the problem. What I discovered is that just connecting multiple times to the server doesn't cause any problems. Neither does adding a select statement after the connection. But when I actually implement a function where is the complete reader part and return my results I run into the time out problems. Here is two examples.
This isn't causing issues:
Private Sub Window_Loaded(sender As System.Object, e As System.Windows.RoutedEventArgs)
Me.DataContext = Me
m_Thread = New Thread(AddressOf ConnectionTestFunction)
m_Thread.IsBackground = True
m_Thread.Start()
End Sub
Private Sub ConnectionTestFunction()
While m_stopThread = False
Try
m_log.WriteLine("GetData (" & m_ThreadCounter & ")")
Using cnn As SqlConnection = New SqlConnection("Data Source=server;Initial Catalog=db;Integrated Security=True;MultipleActiveResultSets=True")
cnn.Open()
Using cmd As SqlCommand = New SqlCommand("SELECT * FROM Data", cnn)
Using DataReader As SqlDataReader = cmd.ExecuteReader()
Do While DataReader.Read()
Loop
End Using
End Using
End Using
Catch ex As Exception
m_log.WriteLine(ex.ToString())
End Try
m_ThreadCounter += 1
Thread.Sleep(1000)
End While
End Sub
This is causing timeout errors:
Private Sub Window_Loaded(sender As System.Object, e As System.Windows.RoutedEventArgs)
Me.DataContext = Me
m_Thread = New Thread(AddressOf ConnectionTestFunction)
m_Thread.IsBackground = True
m_Thread.Start()
End Sub
Private Sub ConnectionTestFunction()
While m_stopThread = False
Try
m_log.WriteLine("GetData (" & m_ThreadCounter & ")")
Dim datarows As List(Of Data) = Me.GetData()
Catch ex As Exception
m_log.WriteLine(ex.ToString())
End Try
m_ThreadCounter += 1
Thread.Sleep(1000)
End While
End Sub
Private Function GetData() As List(Of Data)
Dim result As New List(Of Data)
Using cnn As SqlConnection = New SqlConnection("Data Source=server;Initial Catalog=db;Integrated Security=True;MultipleActiveResultSets=True")
cnn.Open()
Using cmd As SqlCommand = New SqlCommand("SELECT * FROM Data", cnn)
Using DataReader As SqlDataReader = cmd.ExecuteReader()
Do While DataReader.Read()
Dim d As New Data()
d.DataId = DataReader("DataId")
... etc fields about 10 of them ...
result.Add(d)
Loop
End Using
End Using
End Using
Return result
End Function
I'm really happy if anyone have any thoughts about this... I have to admit I'm really confused now.
Probably, your code is taking longer to complete than the default time-out value for the connection is. Try specifying the time-out when you create your Sql Connection. Make sure that it's longer than the time your code needs to complete.
This approach doesn't seem very good.. Instead of pooling, why not react when new data comes? You can use a trigger or SqlDependency?
http://dotnet.dzone.com/articles/c-sqldependency-monitoring