System.InvalidOperationException: 'Operation is not valid due to the current state of the object.' on a update query in vb.net - vb.net

Hello I am trying to do an update query on my database however I end up with this error message
System.InvalidOperationException: 'Operation is not valid due to the current state of the object.'
Here is the code for my search query which I then use in the update
Private Function SearchData(Fname As String, ID As Int32) As DataTable
Dim dt As New DataTable
Dim ds As New DataSet
Dim ssql As String = "SELECT * FROM customers WHERE fname LIKE #Fname OR CustomerID = #ID"
Using con As New SQLiteConnection(ConStr),
cmd As New SQLiteCommand(ssql, con)
con.Open()
cmd.Parameters.Add("#Fname", DbType.String).Value = $"%{Fname}%"
cmd.Parameters.Add("#ID", DbType.Int32).Value = ID
dt.Load(cmd.ExecuteReader)
Dim da As New SQLiteDataAdapter(cmd)
da.Fill(ds, "customers")
dt = ds.Tables(0)
If dt.Rows.Count > 0 Then
ToTextbox(dt)
End If
End Using
Return dt
End Function
This is the ToTextBox function
Public Sub ToTextbox(ByVal newdt)
txtFName.Text = newdt.Rows(0)(1).ToString()
txtLName.Text = newdt.Rows(0)(2).ToString()
mtxtContactNumber.Text = newdt.rows(0)(3).ToString()
txtAddress.Text = newdt.rows(0)(4).ToString()
txtTown.Text = newdt.rows(0)(5).ToString()
txtPostCode.Text = newdt.rows(0)(6).ToString()
End Sub
And the update function
Public Function updateguest(FirstName As String, ID As Integer) As Integer
Dim Result As Integer
Dim usql As String = "UPDATE Customers SET fname = #fname WHERE CustomerID = #ID;"
Using con As New SQLiteConnection(ConStr),
cmd As New SQLiteCommand(usql, con)
con.Open()
cmd.Parameters.Add("#fname", DbType.String).Value = FirstName
cmd.Parameters.Add("#ID", DbType.Int32).Value = ID
con.Open()
Result = cmd.ExecuteNonQuery
con.Close()
End Using
Return Result
End Function
And the Update button
Private Sub IbtnUpdate_Click(sender As Object, e As EventArgs) Handles ibtnUpdate.Click
Try
Dim Result = updateguest(txtFName.Text, CInt(txtSearchID.Text))
If Result > 0 Then
MsgBox("New RECORD HAS BEEN UPDATED!")
Else
MsgBox("NO RECORD HAS BEEN UPDATDD!")
End If
Catch ex As Exception
MsgBox(ex.Message)
End Try
End Sub

I believe you update problems are solved in comments.
You still have too much stuff in your DataAccess code. Just return the DataTable and use it in the user interface code.
Private Function SearchData(Fname As String, ID As Int32) As DataTable
Dim dt As New DataTable
Dim ssql As String = "SELECT * FROM customers WHERE fname LIKE #Fname OR CustomerID = #ID"
Using con As New SQLiteConnection(ConStr),
cmd As New SQLiteCommand(ssql, con)
con.Open()
cmd.Parameters.Add("#Fname", DbType.String).Value = $"%{Fname}%"
cmd.Parameters.Add("#ID", DbType.Int32).Value = ID
dt.Load(cmd.ExecuteReader)
End Using
Return dt
End Function
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim dt = SearchData(FirstNameTextBox.Text, CInt(IDTextBox.Text))
If dt.Rows.Count > 0 Then
ToTextbox(dt)
End If
End Sub
Public Sub ToTextbox(ByVal newdt As DataTable)
txtFName.Text = newdt.Rows(0)(1).ToString()
txtLName.Text = newdt.Rows(0)(2).ToString()
mtxtContactNumber.Text = newdt.Rows(0)(3).ToString()
txtAddress.Text = newdt.Rows(0)(4).ToString()
txtTown.Text = newdt.Rows(0)(5).ToString()
txtPostCode.Text = newdt.Rows(0)(6).ToString()
End Sub

Related

Combobox population does not appear in DataGridView in vb.net

Combobox population does not appear in DataGridView because of the function of DataTable.
below link the previous code running normally with the combobox population.
please recommend the best solution.
I have also coded in my post so it doesn't miss communication
Thanks
link previous post
Private _dt As DataTable
'update code PopulateComboBox in form load
Public Sub New()
If Me.IsInDesignMode() Then
Return
End If
InitializeComponent()
Me.PopulateComboBox()
fillDataGridView1()
End Sub
Private Function GetAndFillDataTable() As DataTable
Dim dt As New DataTable()
Dim query As String = "SELECT NOD,ITM,CIA,DPR,QTY FROM RSD WHERE QTY > 0 AND PNM=#PNM"
Using con As OleDbConnection = New OleDbConnection(GetConnectionString)
Using cmd As OleDbCommand = New OleDbCommand(query, con)
cmd.Parameters.AddWithValue("#PNM", ComboBox1.SelectedValue)
Using da As New OleDbDataAdapter(cmd)
da.Fill(dt)
da.Dispose()
Dim totalColumn As New DataColumn()
totalColumn.DataType = System.Type.GetType("System.Double")
totalColumn.ColumnName = "Total"
totalColumn.Expression = "[CIA]*[QTY]*(1-[DPR]/100)"
dt.Columns.Add(totalColumn)
Return dt
End Using
End Using
End Using
End Function
Private Sub FillDataGridView1()
If (_dt Is Nothing) Then
_dt = GetAndFillDataTable()
End If
grid.DataSource = _dt
grid.Refresh()
End Sub
Private Sub PopulateComboBox()
Dim dt As New DataTable()
Dim query As String = "SELECT DISTINCT PNM FROM RSD UNION SELECT DISTINCT PNM FROM RSG ORDER BY PNM"
Try
dt = New DataTable
Using con As OleDbConnection = New OleDbConnection(GetConnectionString)
Using sda As OleDbDataAdapter = New OleDbDataAdapter(query, con)
sda.Fill(dt)
Dim row As DataRow = dt.NewRow()
row(0) = ""
dt.Rows.InsertAt(row, 0)
ComboBox1.DataSource = dt
ComboBox1.DisplayMember = "PNM"
ComboBox1.ValueMember = "PNM"
End Using
End Using
Catch myerror As OleDbException
MessageBox.Show("Error: " & myerror.Message)
Finally
End Try
'update code combobox selectionchangecommited for fillDataGridView1
Private Sub ComboBox1_SelectionChangeCommitted(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ComboBox1.SelectionChangeCommitted
fillDataGridView1()
End Sub
You are setting your datasource = _dt in PopulateComboBox however the data table you built in your function is called dt.

How to pass arraylist to stored procedure in VB

How to pass an ArrayList to the stored procedure in this code below
Dim sqlcon As SqlConnection = New SqlConnection(ConfigurationManager.ConnectionStrings("connect").ConnectionString)
Dim sda As New SqlDataAdapter
Dim cmd As New SqlCommand
Dim dt As New DataTable
Dim arr As New ArrayList
arr.Add("#type,1") '--------------How do I pass this to my stored procedure
cmd = New SqlCommand("usp_demo", sqlcon)
cmd.CommandType = CommandType.StoredProcedure
sda.SelectCommand = cmd
sda.Fill(dt)
Below is the Stored Procedure used - "usp_demo"
alter procedure usp_demo
#type int
As
Begin
If #type = 1
Begin
select * from sample
End
If #type = 2
Begin
select * from nextnode
End
End
The design of this code depends on how many parameters you need to pass. We don't want the user interface code worrying about the database so we don't want to create SqlParameters in the UI. Let's say you have 5 parameters of different types. Just pass the values to the Function. If there are many parameters, create a class for the entity. Pass an instance of the class with the properties set in the UI code. You could even pass a List(Of YourClass) and loop through it resetting the .Value property of the Parameters.
Simple method as per your question.
Private Function GetData(type As Integer) As DataTable
Dim dt As New DataTable
Using sqlcon As New SqlConnection(),
cmd As New SqlCommand("usp_demo", sqlcon)
cmd.Parameters.Add("#type", SqlDbType.Int).Value = type
cmd.CommandType = CommandType.StoredProcedure
sqlcon.Open()
dt.Load(cmd.ExecuteReader)
End Using
Return dt
End Function
Usage
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim dt = GetData(1)
DataGridView1.DataSource = dt
End Sub
More than on parameter
Private Function InsertRecord(FName As String, LName As String) As Integer
Dim i As Integer
Using cn As New SqlConnection(ConfigurationManager.ConnectionStrings("connect").ConnectionString),
cmd As New SqlCommand("Insert Into Employee (FirstName, LastName) Values (#First, #Last);", cn)
cmd.Parameters.Add("#First", SqlDbType.NVarChar, 100).Value = FName
cmd.Parameters.Add("#Last", SqlDbType.NVarChar, 100).Value = LName
cn.Open()
i = cmd.ExecuteNonQuery
End Using
Return i
End Function
usage
Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
Dim i = InsertRecord("John", "Smith")
If i = 1 Then
MessageBox.Show("Success")
Else
MessageBox.Show("Error")
End If
End Sub
Create a class
Public Class Employee
Public Property FirstName As String
Public Property MiddleName As String
Public Property LastName As String
Public Property DOB As Date
Public Property Weight As Integer
Public Property Department As String
Public Property IsHourly As Boolean
Public Property Rate As Decimal
Public Sub New(FName As String, MName As String, LName As String, Birth As Date, lbs As Integer, Dep As String, Hourly As Boolean, Pay As Decimal)
FirstName = FName
MiddleName = MName
LastName = LName
DOB = Birth
Weight = lbs
Department = Dep
IsHourly = Hourly
Rate = Pay
End Sub
End Class
This class could probably be used other ways in your application.
Private Function InsertCompleteEmployee(e As Employee) As Integer
Dim i As Integer
Dim sql = "Insert Into EmployeeComplete (FirstName, MiddleName, LastName, DOB, Weight, Department, IsHourly, Rate) Values (#FName, #MName, #LName, #Birth, #lbs, #Dep, #Hourly, #Rate);"
Using cn As New SqlConnection(ConfigurationManager.ConnectionStrings("connect").ConnectionString),
cmd As New SqlCommand(sql, cn)
With cmd.Parameters
.Add("#FName", SqlDbType.NVarChar, 100).Value = e.FirstName
.Add("#MName", SqlDbType.NVarChar, 100).Value = e.MiddleName
.Add("#LName", SqlDbType.NVarChar, 100).Value = e.LastName
.Add("#Birth", SqlDbType.Date).Value = e.DOB
.Add("#lbs", SqlDbType.Int).Value = e.Weight
.Add("#Dep", SqlDbType.NVarChar, 100).Value = e.Department
.Add("#Hourly", SqlDbType.Bit).Value = e.IsHourly
.Add("#Rate", SqlDbType.Decimal).Value = e.Rate
End With
cn.Open()
i = cmd.ExecuteNonQuery
End Using
Return i
End Function
Usage
Private Sub Button3_Click(sender As Object, e As EventArgs) Handles Button3.Click
Dim Emp As New Employee(TextBox1.Text, TextBox2.Text, TextBox3.Text, DateTimePicker1.Value, 200, "Accountin", CheckBox1.Checked, 8.5D)
Dim i = InsertCompleteEmployee(Emp)
If i = 1 Then
MessageBox.Show("Success")
Else
MessageBox.Show("Error")
End If
End Sub
The Using...End Using blocks ensure that your database objects are closed and disposed. In these Functions both the connection and the command are part of the block. Note the comma at the end of the Using line.
Always use parameters to avoid sql injection and make the sql string easier to write.
Personally i generally use a key value pair [KeyValuePair(Of String, List(Of SqlParameter))]; I hope that's what you were looking for; probably someone will have a better solution
Public Function ExecuteSelectionSP(ByVal MyConnectionString As String, ByVal KVP As KeyValuePair(Of String, List(Of SqlParameter)), ByRef MyTable As DataTable) As Boolean
Dim Result As Boolean
Dim sqlcon As New SqlConnection(MyConnectionString)
Dim reader As SqlDataReader
Dim cmd As New SqlCommand
cmd.CommandType = CommandType.StoredProcedure
cmd.CommandText = KVP.Key
For Each MyParameter As SqlParameter In KVP.Value
cmd.Parameters.Add(MyParameter)
Next
cmd.Connection = sqlcon
Try
If sqlcon.State = ConnectionState.Closed Then sqlcon.Open()
reader = cmd.ExecuteReader()
MyTable.Load(reader)
If sqlcon.State = ConnectionState.Open Then sqlcon.Close()
Result = True
Catch ex As Exception
MsgBox("Execution error :" & vbCrLf & KVP.Key & vbCrLf & vbCrLf & ex.Message, MsgBoxStyle.Critical, "Errore")
Result = False
End Try
Return Result
End Function

syntax error in false clause and when I search for names nothing displays

One time when I run this code it run smoothly but then when i search for names there is no record appears. Badly need your help guys for our program project. thanks in advance :)
This is my code :
Private Sub search_btn_Click(sender As Object, e As EventArgs) Handles search_btn.Click
Me.Show()
Search_Record()
End Sub
Private Sub Search_Record()
Dim conn As New OleDbConnection
Dim cmd As New OleDbCommand
Dim da As New OleDbDataAdapter
Dim dt As New DataTable
Dim sSQL As String = String.Empty
Try
conn.ConnectionString = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=C:\VB\HSU\HSU\G11B.mdb"
conn.Open()
cmd.Connection = conn
cmd.CommandType = CommandType.Text
sSQL = "SELECT Last_Name, First_Name FROM 10ABM"
sSQL = sSQL & "WHERE Last_Name like '%" & Me.search_txt.Text & "%'"
cmd.CommandText = sSQL
da.SelectCommand = cmd
da.Fill(dt)
Me.DataGridView1.DataSource = dt
If dt.Rows.Count = 0 Then
MsgBox("No record found!")
End If
Catch ex As Exception
MsgBox(ErrorToString)
Finally
conn.Close()
End Try
End Sub

Delete From Table error

i'm trying to create a delete button to delete a record ....
here's my code:
Dim SqlQuery As String = "DELETE FROM MyTable WHERE InvoiceNumber = " & id & ";"
'id is public shared as integer , which is ListView1.SelectedItems(0).Text
Dim SqlCommand As New OleDb.OleDbCommand
With SqlCommand
.CommandText = SqlQuery
.Connection = conn
.ExecuteNonQuery()
End With
I get an exception in .ExecuteNonQuery(), the error is
"ExecuteNonQuery() requires the command to have a transaction" ,
"Validate transaction" , "ExecuteReaderInternal"
assume that the database is connected, got info and delete button is button3 .
Also i will show you my whole form code:
Public Class Report
Public id As Integer
Public conn As New OleDb.OleDbConnection
Public connstring As String = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=C:\Users\Ramy\Documents\Beach.accdb"
Private Property RivieraDataSet As Object
Private Sub Report_FormClosing(sender As Object, e As FormClosingEventArgs) Handles Me.FormClosing
conn.Close()
End Sub
Private Sub Report_Load(sender As Object, e As EventArgs) Handles MyBase.Load
If conn.State = ConnectionState.Closed Then
Try
conn.ConnectionString = connstring
conn.Open()
MsgBox("DataBase opened successfully!", MsgBoxStyle.Exclamation)
loadlistview()
Catch ex As Exception
MsgBox(ex.ToString, MsgBoxStyle.Critical)
End Try
Else
MsgBox("DataBase Error!!", MsgBoxStyle.Critical)
End If
Dim reading As OleDb.OleDbDataReader
Dim cmd As New OleDb.OleDbCommand
Dim trans As OleDb.OleDbTransaction
trans = conn.BeginTransaction
cmd.CommandText = "SELECT * FROM MyTable"
cmd.Connection = conn
cmd.Transaction = trans
reading = cmd.ExecuteReader
Dim i
Do While reading.Read
i = Val(reading.Item("Total")) + i
Loop
TextBox7.Text = i
TextBox7.Text = Convert.ToDecimal(TextBox7.Text).ToString("N2") & " L.E"
End Sub
Sub loadlistview()
ListView1.FullRowSelect = True
ListView1.MultiSelect = False
ListView1.View = View.Details
ListView1.Columns.Clear()
ListView1.Items.Clear()
ListView1.Columns.Add("No", 30, HorizontalAlignment.Left)
ListView1.Columns.Add("InvoiceDate", 125, HorizontalAlignment.Left)
ListView1.Columns.Add("PersonsNumber", 70, HorizontalAlignment.Left)
ListView1.Columns.Add("PersonPrice", 80, HorizontalAlignment.Left)
ListView1.Columns.Add("CashierName", 100, HorizontalAlignment.Left)
ListView1.Columns.Add("Total", 100, HorizontalAlignment.Left)
Dim SqlQuery As String = "SELECT * FROM MyTable"
Dim SqlCommand As New OleDb.OleDbCommand
Dim SqlAdapter As New OleDb.OleDbDataAdapter
Dim table As New DataTable
With SqlCommand
.CommandText = SqlQuery
.Connection = conn
End With
With SqlAdapter
.SelectCommand = SqlCommand
.Fill(table)
End With
For i = 0 To table.Rows.Count - 1
With ListView1
.Items.Add(table.Rows(i)("InvoiceNumber"))
With .Items(.Items.Count - 1).SubItems
.Add(table.Rows(i)("InvoiceDate"))
.Add(table.Rows(i)("PersonsNumber"))
.Add(table.Rows(i)("PersonPrice"))
.Add(table.Rows(i)("CashierName"))
.Add(table.Rows(i)("Total"))
End With
End With
Next
End Sub
Private Sub ListView1_MouseClick(sender As Object, e As MouseEventArgs) Handles ListView1.MouseClick
Dim SqlQuery As String = "SELECT * FROM MyTable"
Dim SqlCommand As New OleDb.OleDbCommand
Dim SqlAdapter As New OleDb.OleDbDataAdapter
Dim table As New DataTable
With SqlCommand
.CommandText = SqlQuery
.Connection = conn
End With
With SqlAdapter
.SelectCommand = SqlCommand
End With
If ListView1.SelectedItems.Count > 0 Then
id = ListView1.SelectedItems(0).Text
TextBox1.Text = id
TextBox6.Text = ListView1.SelectedItems(0).SubItems(1).Text
TextBox3.Text = ListView1.SelectedItems(0).SubItems(2).Text
TextBox4.Text = ListView1.SelectedItems(0).SubItems(3).Text
TextBox2.Text = ListView1.SelectedItems(0).SubItems(4).Text
TextBox5.Text = ListView1.SelectedItems(0).SubItems(5).Text
End If
End Sub
Private Sub Button3_Click(sender As Object, e As EventArgs) Handles Button3.Click
Dim SqlQuery As String = "DELETE FROM MyTable WHERE InvoiceNumber = " & id & ";"
'id is public shared as integer , which is ListView1.SelectedItems(0).Text
Dim SqlCommand As New OleDb.OleDbCommand
With SqlCommand
.CommandText = SqlQuery
.Connection = conn
.ExecuteNonQuery()
End With
End Sub
End Class
I was searching for a mistake in my delete btn code for hours , but i can see everything is good..... but .ExecuteNonQuery() is so annoying .
In your Form_Load you open a transaction for your GLOBAL connection.
This means that every command executed using that connection should be informed of this transaction (and you do it in the Form_Load event setting the Command.Transaction property).
But in other parts of your program, executing a command with that connection and not setting the Transaction property will raise the mentioned error.
Looking at your code above I would suggest to remove altogether the Transaction because, as is, you don't need it.
Simply remove these lines in Form_Load
Dim trans As OleDb.OleDbTransaction
trans = conn.BeginTransaction
...
cmd.Transaction = trans
Instead, if for motives not apparent from the code above, you insist in keeping the Transaction then you should create the command from the connection so the transaction is passed to the command.
Dim SqlQuery As String = "DELETE FROM MyTable WHERE InvoiceNumber = " & id & ";"
Dim SqlCommand = conn.CreateCommand()
With SqlCommand
....
End With
By the way, I really suggest you to remove that global connection variable. It is only a source of problems (check if open, transactions etc...) Just make a function that creates it for you and use it in a Using Statement whenever you need it
Public Function GetConnection() As OleDb.OleDbConnection
Dim conn = New OleDb.OleDbConnection(connstring)
conn.Open()
return conn
End Function
And use it with Using Statement that close and dispose the enclosed object also in case of exceptions
Using conn = GetConnection()
Using command = conn.CreateCommand()
With command
command.CommandText = "DELETE FROM MyTable WHERE InvoiceNumber = " & id & ";"
command.ExecuteNonQuery()
End With
End Using
End Using
Pay also attention at possible sql injection scenarios. In your situation (reading an integer from a ListView) there are few problems, but a parameterized query is always better

specified cast is not valid

Here is a code that retrieve values from the database, but my problem is that it throws out an exception saying "InvalidCastException was unhandled specified cast is not valid". I am now confused what went wrong, The code and the table stated below.
Here is the code:
Public connstring As String = "Provider=Microsoft.ACE.OLEDB.12.0; Data Source =" & Application.StartupPath &
"\TestData.accdb; Persist Security info = false"
Public Conn As New OleDbConnection
Private Sub TestForm_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Loard
Conn.ConnectionString = connstring
Conn.Open()
LoadValue( )
End Sub
Private Sub LoadValue( )
Dim i As Integer
Dim cmd As OleDbCommand = New OleDbCommand
With cmd
.CommandText = "SELECT MAX(Guard_ID) FROM Guard"
.CommandType = CommandType.Text
.Connection = Conn
.ExecuteNonQuery()
Dim reader As OleDbDataReader = cmd.ExecuteReader
If reader.Read Then
TextBox1.Text = reader.GetString(0)
i = TextBox1.Text + 1
TextBox1.Text = i
reader.Close()
End If
End With
End Sub
The table reference:
Exception Error:
I am really confused now on why the code does not work, any help and advice will be gladly accepted. Thanks in advance.
try this,
Private Sub LoadValue()
Dim i As Integer
Dim cmd As OleDbCommand = New OleDbCommand
With cmd
.CommandText = "SELECT MAX(Guard_ID) FROM Guard"
.CommandType = CommandType.Text
.Connection = Conn
.ExecuteNonQuery()
Dim reader As OleDbDataReader = cmd.ExecuteReader
If reader.Read Then
Dim tmpVal As Object = reader.Item(0)
TextBox1.Text = IIf(IsDBNull(tmpVal), "0", tmpVal.ToString())
i = CInt(TextBox1.Text) + 1
TextBox1.Text = i.ToString()
reader.Close()
End If
End With
End Sub