Collection was modified; enumeration operation may not execute. VB.Net - vb.net

There are a lot of questions that are a duplicate of this question, but none of them seem to actually answer my specific problem.
I am writing an IRC bot, and i am adding users to a List(Of String) as you can see in the below code. However, when i want to go through a foreach loop of the users on another thread, i get the error in the title. I have even put a boolean in place to stop it from adding users, yet it still says it is being modified somehow. Any help would be greatly appreciated.
(Before you read the code, keep in mind i am new to VB.net, and even if it messy, i'd prefer to not be bashed for it as i am new)
Sub Handler()
handlerActive = True
Dim list As New List(Of String)
query = "SELECT * FROM " & channel.Substring(1)
Try
connHost.Close()
Catch
End Try
connHost.Open()
Dim cmd As MySqlCommand = New MySqlCommand(query, connHost)
Dim dataReader As MySqlDataReader = cmd.ExecuteReader()
While (dataReader.Read())
list.Add(dataReader.GetString(1))
End While
dataReader.Close()
If (users.Count > 0) Then
For Each user2 In users
Try
connHost.Close()
Catch ex As Exception
End Try
connHost.Open()
query = ("UPDATE `" & channel.Substring(1) & "` SET `Amount` = Amount + 1 WHERE `Username`='" & user2 & "'")
cmd = New MySqlCommand(query, connHost)
Try
cmd.ExecuteNonQuery()
Catch
Console.WriteLine("Failed to update user - " & user2)
End Try
Next
End If
connHost.Close()
handlerActive = False
End Sub
Below here is where i add users to my List called "users"
If (handlerActive = False And users.Contains(user) = False And user.Trim().CompareTo("") <> 0 Or user.Trim().CompareTo("jtv") <> 0 Or user.Trim().Contains(" ") = False Or user.Trim().Contains(".") = False) Then
users.Add(user)
End If

Related

Trying to display a warning message on a btnsubmit_click function in vb.net when the invoice is in use

The sql script is validating the use of the invoice type and invoice. I need to add the check and message in the If (Me.txtMasterId.Text <> "0") method..
Protected Sub btnsubmit_Click(sender As Object, e As EventArgs) Handles btnsubmit.Click
If (Not DataForm.ValidateForm) Then
TransRepo.ModifyStatusName(gUser.CompanyId, Me.txtMasterId.Text, Me.txtStatusName.Text, chkIsPmtPlanFee.Checked, chkIsAttorneyFee.Checked, Me.cboStatus.SelectedValue, Me.txtId.Text, ParseDec(Me.txtExpenseLimit.Text), chkUserSpecPayTo.Checked)
ShowPanel(Me.pnlItemList, Me.Form)
ListOptions(Me.txtMasterId.Text)
SetPageHeader("List Status Name")
If (Me.txtId.Text = "0") Then
ShowConfirmation(Me.lblItemFrmMsg, "New name Added")
If (Me.txtMasterId.Text <> "0") Then
ShowConfirmation(Me.lblItemFrmMsg, "Status Name Saved")
Else
DataForm.DisplayError(Me.lblFrmErr)
End If
End If
End If
End Sub
Dim cn As MySqlConnection
Dim rdr As MySqlDataReader
Try
Dim Sql = "SELECT invoice_type.id
FROM invoice_type_fee
INNER JOIN invoice_name ON invoice_type.id = invoice_type_fee.`id`
WHERE invoice_name.`is_active` = 1
AND invoice_type_fee.`is_active` = 1
AND (invoice_type_fee.`fee_invoice_id` = #invoiceTyID
OR invoice_type_fee.`fee_late_invoicetype_id` = #invoiceTypeID LIMIT 1"
rdr.Read()
If (rdr.HasRows) Then
Dim message As String = "....."
Status.Visible = False
ClientScript.RegisterStartupScript(Me.GetType(), "alert", "alert('" & message & "');", True)
'If (invoicetype = "1") Then
End If
Catch ex As Exception
Throw
End Try
End Sub
There is no reader. You never call ExecuteReader so there's no reader to read. You seem to think that it is Read that executes the SQL but it is not. ExecuteReader executes the SQL and then Read is used to get the data from the result set. I just realised that there isn't even a command in your case. You need to create a command to execute, execute it, then read the results
There's no point getting any data though, because all you care about is whether there is data, not what it is. That means that HasRows is all you need in that case, e.g.
Using connection As New MySqlConnection("connection string here"),
command As New MySqlCommand(sql, connection)
connection.Open()
Using reader = command.ExecuteReader()
If reader.HasRows Then
'The query produced a non-empty result set.
End If
End Using
End Using
A better option would be to add a COUNT to your SQL, call ExecuteScalar and then check whether the result is zero or not.
Dim Sql = "SELECT COUNT(invoice_type.id)
FROM invoice_type_fee
INNER JOIN invoice_name ON invoice_type.id = invoice_type_fee.`id`
WHERE invoice_name.`is_active` = 1
AND invoice_type_fee.`is_active` = 1
AND (invoice_type_fee.`fee_invoice_id` = #invoiceTyID
OR invoice_type_fee.`fee_late_invoicetype_id` = #invoiceTypeID LIMIT 1"
Using connection As New MySqlConnection("connection string here"),
command As New MySqlCommand(sql, connection)
connection.Open()
If CInt(command.ExecuteScalar()) > 0 Then
'There are matching records.
End If
End Using

Failed to read when no data is present

i have this code,,its work (kind of).
Dim connString As String = ConfigurationManager.ConnectionStrings("connectionstring").ConnectionString
Dim conn As New SqlConnection(connString)
conn.Open()
Dim comm As New SqlCommand("SELECT username, Password,type FROM users WHERE username='" & TextBox1.Text & "' AND Password='" & TextBox2.Text & "'", conn)
Dim reader As SqlDataReader
reader = comm.ExecuteReader
Dim count As Integer
count = 0
While reader.Read
count = count + 1
End While
If count = 1 Then
MessageBox.Show("username and password are correct")
Form2.Show()
Form2.Label1.Text = Me.TextBox1.Text
Form2.Label2.Text = reader(2).ToString
ElseIf count > 1 Then
MessageBox.Show("username and password are duplicated")
Else
MessageBox.Show("username and password are wrong")
End If
im getting error with this line:
Form2.Label2.Text = reader(2).ToString
and error is "Invalid attempt to read when no data is present"
why its says "no data"
i have all data in database?
can someone help me to correct this code?
thank you ..
You should not be using a loop at all. There should be no way that you can get more than one record so what use would a loop be? You should be using an If statement and that's all:
If reader.Read() Then
'There was a match and you can get the data from reader here.
Else
'There was no match.
End If
If it's possible to have two records with the same username then there's something wrong with your database design and your app. That column should be unique and your app should be testing for an existing record when someone tries to register.
A SqlDataReader is a forward only data read element. The error is occurring because you're calling the reader's READ function twice; once as true to increment to 1, and a second time to get a false to fall out of the while statement. Since you're no longer in the WHILE statement, the reader had to have read the end of the result set, thus there is no data for you to read.
Consider the changed code below:
Dim connString As String = ConfigurationManager.ConnectionStrings("connectionstring").ConnectionString
Dim count As Integer = 0
Dim userType as string = ""
Using conn As New SqlConnection(connString)
conn.Open()
Using Comm as SqlCommand = conn.CreateCommand
comm.commandText = "SELECT username, Password, type FROM Users WHERE username = #UserName AND Password = #Pwd; "
comm.parameters.AddWithValue("#Username", TextBox1.Text)
comm.parameters.AddWithValue("#Password", Textbox2.text)
Dim reader As SqlDataReader
reader = comm.ExecuteReader
If reader IsNot Nothing Then
If reader.HasRows() Then
While reader.read
count = count + 1
If Not reader.IsDbNull(2) Then userType = reader(2).ToString
End While
End If
If Not reader.IsClosed Then reader.close
reader = Nothing
End If
End Using
End Using
If count = 1 Then
MessageBox.Show("username and password are correct")
Form2.Show()
Form2.Label1.Text = Me.TextBox1.Text
Form2.Label2.Text = userType
ElseIf count > 1 Then
MessageBox.Show("username and password are duplicated")
Else
MessageBox.Show("username and password are wrong")
End If
First off, SQLParameters are your friend. Learn them. They are the single easiest way to fight against SQL Injection when using the SqlClient classes.
Secondly, notice that I'm doing the actual retrieval of the data from the reader inside the WHILE loop. This ensures that there's actual data for me to read.
Third, notice the USING statements on the SqlConnection and SqlCommand objects. This helps with garbage collection, and has a couple of other benefits as well.
Finally, notice the checks I'm doing on the SqlDataReader before I ever attempt to access it. Things like that would prevent from another error appearing if you did not return any results.

Slow database query: Using VB.net connecting to Access

I have a program which will only allow a certain amount of concurrent users to use the program at one time. To do this I have a single table in an access database which holds each user that is using the program. Now although this does work the query seems to be running very slowly, I am certain it is something to do with the database functions as it was running fine before I implemented them.
Here are my functions:
Public Function openDB() As Boolean
cnn.Open()
Return True
End Function
Public Function closeDB() As Boolean
cnn.Close()
Return True
End Function
Then there is the function for checking the database. This is where I think it may be tripping up because I have 2 queries running here:
Public Function CheckLicence() As Boolean
Dim result As Boolean = HandleRegistry()
If result = True Then
Dim _table As String = "Users"
Dim query As String = "SELECT * FROM " & _table & " WHERE Machine_ID='" & CpuId() & "'"
Dim sizeQuery As String = "SELECT COUNT(*) FROM " & _table
Dim NoUsers As Integer = 0
Dim ds As New DataSet
Dim dr As OleDbDataReader
Dim cmd As New OleDbCommand(query, cnn)
dr = cmd.ExecuteReader
Dim sizeCdm As New OleDbCommand(sizeQuery, cnn)
NoUsers = sizeCdm.ExecuteScalar()
If dr.Read() Then
Return True
Else
If NoUsers < My.Settings.NoUsers Then
addToDB()
Else
MsgBox("Too many users are currently using this program. Clear a user and try again.")
Return False
End If
End If
Else
MsgBox("Your licence has expired, contact support to purchase a new licence.")
Return False
End If
Return True
End Function
And to add and remove I have to get the cpu id, I found the code for that on here somewhere it does work but maybe that could be the slow part, I dont actually know if this is the correct way of getting it.
Public Sub addToDB()
Dim _table As String = "Users"
Dim query As String = "INSERT INTO " & _table & " ([User], [Machine_ID]) VALUES (?,?)"
Dim ds As New DataSet
Dim cmd As New OleDbCommand(query, cnn)
cmd.Parameters.AddWithValue("?", Environment.UserName)
cmd.Parameters.AddWithValue("?", CpuId())
cmd.ExecuteNonQuery()
End Sub
Public Sub RemoveFromDB()
Dim _table As String = "Users"
Dim query As String = "DELETE * FROM " & _table & " WHERE Machine_ID='" & CpuId() & "'"
Dim ds As New DataSet
Dim cmd As New OleDbCommand(query, cnn)
cmd.ExecuteNonQuery()
End Sub
Private Function CpuId() As String
Dim computer As String = "."
Dim wmi As Object = GetObject("winmgmts:" &
"{impersonationLevel=impersonate}!\\" &
computer & "\root\cimv2")
Dim processors As Object = wmi.ExecQuery("Select * from " &
"Win32_Processor")
Dim cpu_ids As String = ""
For Each cpu As Object In processors
cpu_ids = cpu_ids & ", " & cpu.ProcessorId
Next cpu
If cpu_ids.Length > 0 Then cpu_ids =
cpu_ids.Substring(2)
Return cpu_ids
End Function
How about storing the cpuID globally and fetching only once. Also, use the Using construct on anything that needs to be disposed. Lastly, run a few StopWatches around your methods to see which one is slow or just debug through each one to find the slow method.
Answer:
How about storing the cpuID globally and fetching only once. Also, use the Using >construct on anything that needs to be disposed. Lastly, run a few StopWatches >around your methods to see which one is slow or just debug through each one to >find the slow method. – Andrew Mortimer
Moved the call for getting the cpuID to the program initialisation so that it runs on startup. This made it run much faster than it did before.

Issues with deleting records and data reading using vb.net

I'm very new to programming and I'm at the very end of my first vb.net programming assignment but I can't figure this last part out.
The program is a small address book with database back-end, my problem occurs when I delete a contacts record.
The data record being read is based off the contacts primary key, when I delete a contact record the next contact record moves up but every record below it doesn't read correctly.
I have a feeling this occurs because my code only reads the primary keys in sequential order, but I'm not sure how to go about changing it to make it work correctly.
Here's the code that relates to it reading the data when i select the record in a listview.
Private Sub ListView1_SelectedIndexChanged_1(sender As Object, e As EventArgs) Handles ListView1.SelectedIndexChanged
Dim command As MySqlCommand = Nothing
Dim reader As MySqlDataReader
Dim query As String = "SELECT * FROM contacts WHERE id= '" & ListView1.FocusedItem.Index + 1 & "'"
Try
connection.Open()
command = New MySqlCommand(query, connection)
reader = command.ExecuteReader
While reader.Read
txtFirstName.Text = reader.GetString("first_name")
txtSurname.Text = reader.GetString("surname")
txtHouseNo.Text = reader.GetString("house_number")
txtStreet.Text = reader.GetString("street")
txtSuburb.Text = reader.GetString("suburb")
cboState.Text = reader.GetString("state")
txtPhone.Text = reader.GetString("phone")
txtMobile.Text = reader.GetString("mobile")
txtWork.Text = reader.GetString("work")
txtEmail.Text = reader.GetString("email")
txtNotes.Text = reader.GetString("notes")
txtid.Text = reader.GetString("id")
End While
Catch ex As MySqlException
MessageBox.Show(ex.Message)
Finally
connection.Close()
command.Dispose()
End Try
Call txtEnable()
End Sub
And here's how I load the contacts to the listview
Private Sub loadcontacts()
Dim command As MySqlCommand = Nothing
Dim listquery As String = "SELECT * FROM contacts ORDER BY id"
Dim reader As MySqlDataReader = Nothing
Try
If connection.State = ConnectionState.Closed Then
connection.Open()
End If
command = New MySqlCommand(listquery, connection)
reader = command.ExecuteReader()
command.CommandText = listquery
With ListView1
.Columns.Add("Name", 220, HorizontalAlignment.Left)
End With
ListView with the data
While reader.Read
Dim ls As New ListViewItem(reader.Item("first_name").ToString() & " " & reader.Item("surname").ToString)
ListView1.Items.Add(ls)
End While
Catch ex As MySqlException
Finally
connection.Close()
command.Dispose()
End Try
End Sub
Thanks for any help.
After you delete a record, clear and reload your list.
For anyone that has a similar problem I figured it out.
Steve helped me get on the right track here so thank you.
I added the ID (primary key) subitem like this:
While reader.Read
Dim ls As New ListViewItem(reader.Item("first_name").ToString() & " " & reader.Item("surname").ToString)
ls.SubItems.Add(reader.Item("id").ToString)
ListView1.Items.Add(ls)
then in the listview focused item I made the query like this:
Dim query As String = "SELECT * FROM contacts WHERE id = '" & ListView1.FocusedItem.SubItems(1).Text & "'"
Now save, update, and delete work with primary key ID reading in the correct order. Thanks for the help and I hope this helps out someone in the future

Why is my ELSE statement being skipped?

I've been trying to use an IF/ELSE statement to query my MySQL database, but can't seem to figure out why the ELSE statement is being ignored by VB. Here's the code - any help would be appreciated:
dbConn = New MySqlConnection("Server=" & FormLogin.ComboBoxServerIP.SelectedItem & ";Port=3306;Uid=qwertyuiop;Password=lkjhgfdsa;Database=zxcvbnm")
Dim account As Boolean = True
If dbConn.State = ConnectionState.Open Then
dbConn.Close()
End If
dbConn.Open()
Dim dbQuery As String = "SELECT * FROM customer WHERE accountNumber = '" & TextBoxSearch.Text & "';"
Dim dbData As MySqlDataReader
Dim dbAdapter As New MySqlDataAdapter
Dim dbCmd As New MySqlCommand
dbCmd.CommandText = dbQuery
dbCmd.Connection = dbConn
dbAdapter.SelectCommand = dbCmd
dbData = dbCmd.ExecuteReader
While dbData.Read()
If dbData.HasRows() = True Then
MessageBox.Show("Customer Account Found!")
Else
MessageBox.Show("No Customer Records Found! Please try again!")
dbData.Close()
End If
End While
My intent is to replace the messagebox in the "IF" clause with the code that will populate my form with the data from the database.
That's because you are already reading it:
While dbData.Read()
If dbData.HasRows() = True Then
MessageBox.Show("Customer Account Found!")
Else
MessageBox.Show("No Customer Records Found! Please try again!")
dbData.Close()
End If
End While
If your reader has no records, the whole While loop will be skipped.
Try it the other way around:
If dbData.HasRows Then
While dbData.Read()
'looping through records here
End While
Else
MessageBox.Show("No Customer Records Found! Please try again!")
End If
And also the obligatory note: Don't keep your connections open and alive. Use the Using End Using bracket to automatically close your disposable objects.
I wouldn't say it's skipping your else clause, but it could be evaluating your if condition differently that you expect.
Personally, I don't like comparing anything to True. If you drop the = true, does it work?