Open DataReader associated with this Connection which must be closed first - mysql

I am trying to make a POS (Point of Sales) Application and I got this error. "There is already an open DataReader associated with this Connection which must be closed first."
Below are my codes:
Database using MySQL
If txt_notr.Text = "" Or txt_kodep.Text = "" Or txt_item.Text = "" Or txt_gt.Text = "" Or txt_bayar.Text = "" Then
MsgBox("Data belum lengkap...!!!")
Exit Sub
Else
'Simpan ke tabel penjualan
db.Close()
db.Open()
Call Koneksi()
Dim simpan1 As String = "Insert Into tb_penjualan values('" & txt_notr.Text & "','" & Format(Now, "yyyy-MM-dd") & "','" & txt_kodep.Text & "','" & txt_item.Text & "','" & txt_gt.Text & "','" & txt_bayar.Text & "')"
cmd = New MySqlCommand(simpan1, db)
cmd.ExecuteNonQuery()
db.Close()
db.Open()
'Simpan ke tabel detail penjualan
For baris As Integer = 0 To DGV.Rows.Count - 2
Dim simpandet As String = "Insert into tb_detjual values('" & txt_notr.Text & "','" & DGV.Rows(baris).Cells(0).Value & "','" & DGV.Rows(baris).Cells(3).Value & "','" & DGV.Rows(baris).Cells(4).Value & "','" & DGV.Rows(baris).Cells(5).Value & "')"
cmd = New MySqlCommand(simpandet, db)
cmd.ExecuteNonQuery()
db.Close()
db.Open()
cmd = New MySqlCommand("Select * from tb_stok where id_obat = '" & DGV.Rows(baris).Cells(0).Value & "'", db)
dr = cmd.ExecuteReader
dr.Read()
If dr.HasRows Then
Dim kurangstok As String = "Update tb_stok set stok = '" & dr.Item("stok") - DGV.Rows(baris).Cells(4).Value & "' where id_obat = '" & DGV.Rows(baris).Cells(0).Value & "'"
cmd = New MySqlCommand(kurangstok, db)
cmd.ExecuteNonQuery() 'The Error shows here...
End If
Next
Call hapustemp()
Call bersih()
Call notrans()
End If
db.Close()

It's counter-intuitive, but ADO.Net providers use a feature called Connection Pooling, such that you really are better off creating a new connection object in most cases for individual calls to a database, rather than trying to keep a single database connection in your class to re-use. The code below shows the correct way to re-use the connection object: create a new connection for the method, and use it for the duration of the method. But then let the connection be collected when the method completes.
I noticed that you also have some seriously insecure code. Before doing any more work with databases, you should read up on Sql Injection. This is a HUGE issue. You should not be writing database code professionally if you don't know about it, and the correct way to avoid the problem.
Finally, the code uses some conventions that originated with older VBScript/VB6 and are no longer appropriate.
The code below solves all of those issues, and should be much faster by avoiding the need to run a SELECT from the database for each gridview row:
If String.IsNullOrWhiteSpace(txt_notr.Text) OrElse String.IsNullOrWhiteSpace(txt_kodep.Text) OrElse String.IsNullOrWhiteSpace(txt_item.Text) OrElse String.IsNullOrWhiteSpace(txt_gt.Text) OrElse String.IsNullOrWhiteSpace(txt_bayar.Text_ Then
MsgBox("Data belum lengkap...!!!")
Exit Sub
End If
'No need for an "Else". The "Exit Sub" takes care of it.
'Simpan ke tabel penjualan
'Note that I was able to let the database set the time stamp
Dim sql As String = "Insert Into tb_penjualan values(#notr, current_timestamp, #kodep, #item, #gt, #bayar);"
'The "Using" keyword will guarantee the connection closes, even if an exception is thrown
Using cn As New MySqlConnection(" connection string here "), _
cmd As New MySqlCommand(sql, cn)
'Use parameter placeholders rather than string concatenation. This avoids a SERIOUS security issue.
' I have to guess parameter types/lengths, but you should use actual types/lengths that match your database
cmd.Parameters.Add("#notr", MySqlDbType.Int32).Value = CInt(txt_notr.Text)
cmd.Parameters.Add("#kodep", MySqlDbType.VarChar, 20).Value = txt_kodep.Text
cmd.Parameters.Add("#item", MySqlDbType.VarString, 1000).Value = txt_item.Text
cmd.Parameters.Add("#gt", MySqlDbType.VarChar, 50).Value = txt_gt.Text
cmd.Parameters.Add("#bayar", MySqlDbType.VarChar, 50).Value = txt_bayar.Text
cn.Open()
cmd.ExecuteNonQuery()
'Two sql statements in a single call to the database.
'This is MUCH better than the Insert/Select/Update process you were using
sql = "INSERT INTO tb_detjual VALUES (#notr, #c0, #c3, #c4, #c5);" & _
"UPDATE tb_stok SET stok = stok - #c4 WHERE id_obat = #c0;"
'See how I was able to re-use the same parameters in the query.
cmd.Parameters.Clear()
cmd.CommandText = sql
cmd.Parameters.Add("#notr", MySqlDbType.Int32).Value = CInt(txt_notr.Text)
cmd.Parameters.Add("#c0", MySqlDbType.VarChar, 50)
cmd.Parameters.Add("#c3", MySqlDbType.VarChar, 50)
cmd.Parameters.Add("#c4", MySqlDbType.VarChar, 50)
cmd.Parameters.Add("#c5", MySqlDbType.VarChar, 50)
'Simpan ke tabel detail penjualan
For baris As Integer = 0 To DGV.Rows.Count - 2
'I'm able to re-use the same parameters for each loop
cmd.Parameters("#c0").Value = DGV.Rows(baris).Cells(0).Value
cmd.Parameters("#c3").Value = DGV.Rows(baris).Cells(3).Value
cmd.Parameters("#c4").Value = DGV.Rows(baris).Cells(4).Value
cmd.Parameters("#c5").Value = DGV.Rows(baris).Cells(5).Value
cmd.ExecuteNonQuery()
Next
End Using
hapustemp()
bersih()
notrans()

Related

VB.NET Getting Duplicate in Inserting data in mysql

I'm trying to insert data in MYSQL and get the latest ID but the problem is I'm Inserting Duplicate data
Is my syntax is wrong or something?
connection.Open()
insertString = "INSERT INTO `daily_report`(`saan_nalaman`,`purpose`, `usual_time`, `apps`,`feedback`,`userid`, `survey_at_what_blh`) VALUES ('" & txtq1.Text & "', '" & txtq2.Text & "', '" & txtq3.Text & "', '" & txtq4.Text & "', '" & txtq5.Text & "', '" & Utilities.UserID & "', '" & Login.RichTextBox1.Text & "');SELECT last_insert_id();"
command = New MySqlCommand(insertString, connection)
reader = command.ExecuteReader
connection.Close()
connection.Open()
TextBox1.Text = command.ExecuteScalar
connection.Close()
Declare and dispose your database objects in the method where they are used. Using blocks handle this for us even if there is an error. Always use parameters to avoid sql injection. Also, it makes the sql command easier to read and write without all the concatenation and single quotes. A single ExecuteScalar will accomplish both the insert and the select.
Private ConStr As String = "Your connection string"
Private Sub GetID()
Dim insertString = "INSERT INTO `daily_report`(`saan_nalaman`,`purpose`, `usual_time`, `apps`,`feedback`,`userid`, `survey_at_what_blh`) VALUES (#saan, #purpose, #time, #apps, #feedback, #userid, #survey) SELECT last_insert_id();"
Dim id As Integer
Using Command As New MySqlCommand(insertString, New MySqlConnection(ConStr))
With Command.Parameters
.AddWithValue("#saan", txtq1.Text)
.AddWithValue("#purpose", txtq2.Text)
.AddWithValue("#time", txtq3.Text)
.AddWithValue("#apps", txtq4.Text)
.AddWithValue("#feedback", txtq5.Text)
.AddWithValue("#userid", Utilities.UserID)
.AddWithValue("#survey", Login.RichTextBox1.Text)
End With
Command.Connection.Open()
id = CInt(Command.ExecuteScalar)
End Using
TextBox1.Text = id.ToString
End Sub

Insert data to MySql and display in datagridveiw

Recently i developed a pos but i have an problem inserting the data and displaying the names of the table in datagrid view
here is some code :
Dim Query As String
Query = "insert into baza.artikli(barkod,naziv,kupovna,prodazna,kolicina,proizvoditel,opis) values ('" & TextBoxBarkod.Text & "','" & TextBoxNaziv.Text & "','" & kupovnacena & "','" & prodaznacena & "','" & kolicina & "','" & TextBoxProizvoditel.Text & "','" & TextBoxOpis.Text & "')"
COMMAND = New MySqlCommand(Query, konekcija)
READER = COMMAND.ExecuteReader
MessageBox.Show("Артиклот е успешно внесен !")
TextBoxBarkod.Text = ""
TextBoxKupovna.Text = ""
TextBoxNaziv.Text = ""
TextBoxOpis.Text = ""
TextBoxProdazna.Text = ""
TextBoxProizvoditel.Text = ""
TextBoxKolicina.Text = ""
konekcija.Close()
Catch ex As Exception
MessageBox.Show(ex.Message)
Finally
konekcija.Dispose()
And i tried:
Private Sub prikazitabela()
konecija = New MySqlConnection
konecija.ConnectionString =
"server=localhost;userid=root;password=root;database=bazaartikli123"
Dim SDA As New MySqlDataAdapter
Dim bazaDataSet As New DataTable
Dim bajndsors As New BindingSource
Try
konecija.Open()
Dim Query As String
Query = "select barkod as 'Баркод',naziv as 'Назив на артикал',kupovna as 'Куповна цена',prodazna as 'Продажна цена',opis as'Опис',ddv as 'ДДВ',makproizvod as 'Македонски прозивод' from bazaartikli123.artikli"
COMMAND = New MySqlCommand(Query, konecija)
SDA.SelectCommand = COMMAND
SDA.Fill(bazaDataSet)
bajndsors.DataSource = bazaDataSet
DataGridView1.DataSource = bajndsors
SDA.Update(bazaDataSet)
konecija.Close()
Catch ex As Exception
MessageBox.Show(ex.Message)
Finally
konecija.Dispose()
End Try
End Sub`
There are several things that can be improved, starting with using SQL parameters and executing your query:
Dim Query As String = <sql>
insert into baza.artikli
(barkod,naziv,kupovna,prodazna,kolicina,proizvoditel,opis)
values (#p1,#p2,#p3,#p4,#p5,#p6,#p7 )
</sql>.Value
Using dbcon As New MySqlConnection(MySQLConnStr)
Using cmd As New MySqlCommand(Query, dbcon)
' I dont really know what datatype these really are
cmd.Parameters.Add("#p1", MySqlDbType.VarChar).Value = TextBoxBarkod.Text
cmd.Parameters.Add("#p2", MySqlDbType.DateTime).Value = DTPNaziv.Value
cmd.Parameters.Add("#p3", MySqlDbType.Int32).Value = Convert.ToInt32(Textkupovna.Text)
' ...
dbcon.Open()
' this was missing:
cmd.ExecuteNonQuery()
End Using
dt = New DataTable
Using cmd As New OleDbCommand("SELECT * FROM baza.artikli")
dt.Load(cmd.ExecuteReader())
dgv2.DataSource = dt
End Using
End Using
I used an XML literal for the SQL mainly to avoid scrolling here, but it can make your code much more readable
There is little context for the code in the question, but connections ought be created as needed; DBCommand objects are highly query specific, so they too ought be created as needed rather than using global ones.
Use Using blocks to assure that DbConnections and other objects with a Dispose() method are properly disposed. The code closes, but does not Dispose of the connection.
Use SQL Parameters always. These assure the correct data type is passed, avoid the cruft of " Foo -'" & foovar & "' AND ..." in code, protect against special characters in strings as well as prevent SQL injection attacks.
Then cmd.ExecuteNonQuery() performs the insert.
After that, you can run a new query to get whatever data you want to display. Note that you do not need to create a DataAdapter to fill a table. It is not clear what you want to display, so that will also have to be modified for what you want.
When AutoGenerateColumns is True, they will be created when you set the datasource and the column names (== 'names of the table' ?) will automatically show. If you want different text to display for the headers, you can either set them manually or uses aliases for them in your SQL, as shown on a previous answer

Inserting query results from MS SQL 2008 to MYSQL via VB2010

Im a newbie in VB2010 & in MYSQL Database.
I have 2 database one on MS SQL 2008 (BigData) and another on Mysql. I have written some code in VB2010 to fetch data from SQL2008 and insert into MySQL. My goal is to transfer all data from MS SQL to MySQL as quick as I can thats why I created a simple vb script that will act as middleware to transfer data from MS SQL to MySQL.
My Headache is, almost 1 hour to transfer the 28,000 records from MS SQL to MySQL database. Is there any easiest way to transfer the data or I need to enhance my VBScript program. Please help to improve my VBScript below.
Thank you in advance.
Imports MySql.Data.MySqlClient
Imports System.Data
Imports System.Data.SqlClient
Public Class Form1
Dim SQLConnectionSQL As MySqlConnection = New MySqlConnection
Dim connectionStringSQL As String = "Data Source=solomon;Initial Catalog=testapp;Persist Security Info=True;User ID=sa;Password=Passw0rd"
Dim connectionString As String = "Server=192.168.1.199; User Id=gil; Password=Passw0rd; Database=testapp"
Dim SQLConnection As MySqlConnection = New MySqlConnection
Dim oDt_sched As New DataTable()
Private Sub btnRetrieve_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnRetrieve.Click
Dim con_Solomon As String
Dim connection As SqlConnection
Dim command As SqlCommand
Dim adapter As New SqlDataAdapter
Dim ds As New DataSet
Dim sql As String
Dim str_carSql As String
lblCounter.Text = 0
con_Solomon = "Data Source=solomon;Initial Catalog=MARYLANDAPP;Persist Security Info=True;User ID=sa;Password=Passw0rd"
sql = "SELECT LTRIM(RTRIM(DocType)) as DocType, LTRIM(RTRIM(cust_classID)) as cust_classID, LTRIM(RTRIM(salesman)) as salesman, LTRIM(RTRIM(CustId)) as CustId, LTRIM(RTRIM(name)) as name, LTRIM(RTRIM(ClassID)) as ClassID, LTRIM(RTRIM(invoice_no)) AS refnbr, invoice_delv_date AS Delv_DocDate, Age, AR_Amount, LTRIM(RTRIM(STATUS)) as STATUS, LTRIM(RTRIM(AGE_GROUP)) as AGE_GROUP, LTRIM(RTRIM(company)) AS comp, '' AS Deposit_Date, Credit_Limit, LTRIM(RTRIM(Terms)) as Terms, LTRIM(RTRIM(customer_name)) AS ShipName, LTRIM(RTRIM(PO_Number)) as PO_Number, LTRIM(RTRIM(Kob)) as Kob, LTRIM(RTRIM(check_date)) as check_date FROM a_aging_ardoc_report"
connection = New SqlConnection(con_Solomon)
Try
connection.Open()
command = New SqlCommand(sql, connection)
command.CommandTimeout = 420
adapter.SelectCommand = command
adapter.Fill(ds, "PO_Monitoring")
adapter.Dispose()
command.Dispose()
connection.Close()
''****** MYSQL CONNECTION *****
SQLConnection = New MySqlConnection()
SQLConnection.ConnectionString = connectionString
SQLConnection.Open()
Dim sqlCommand As New MySqlCommand
Dim delv_docdate, check_date
For a = 0 To ds.Tables(0).Rows.Count - 1
With ds.Tables(0).Rows(a)
If Not IsDBNull(.Item(7)) Then
delv_docdate = .Item(7)
Else
delv_docdate = ""
End If
If Not IsDBNull(.Item(19)) Then
check_date = .Item(19)
Else
check_date = ""
End If
str_carSql = "insert into agingreportsummary(doctype,cust_classid,salesman,custId,name,classid,refnbr,delv_docdate,age,ar_amount,status,age_group,comp,credit_limit,terms,shipname,po_number,kob,check_date) " & _
"VALUES('" & .Item(0) & "','" & .Item(1) & "','" & Replace(.Item(2), "'", "") & "','" & .Item(3) & "','" & Replace(.Item(4), "'", "") & "','" & Replace(.Item(5), "'", "") & "','" & .Item(6) & "','" & delv_docdate & "'," & Replace(.Item(8), ",", "") & "," & Replace(.Item(9), ",", "") & ",'" & Replace(.Item(10), "'", "") & "','" & .Item(11) & "','" & .Item(12) & "','" & .Item(14) & "','" & .Item(15) & "','" & Replace(.Item(16), "'", "") & "','" & Replace(.Item(17), "'", "") & "','" & .Item(18) & "','" & check_date & "');"
End With
sqlCommand.Connection = SQLConnection
sqlCommand.CommandText = str_carSql
sqlCommand.ExecuteNonQuery()
Next a
SQLConnection.Close()
MsgBox("Finish")
Catch ex As Exception
MsgBox(str_carSql)
MsgBox(ex.Message)
End Try
End Sub
End Class
You can try using a parameterised query instead of building a query for each row. That should improve things slightly since the statement wouldn't need to be prepared every time.
Add all the required parameters to the command.
Set the command text once, and change it to use parameters.
Inside the loop you would only set the parameter values and call the executenonquery method
This would have the added benefit of not being vulnerable to sql injection.
Hope that helps

mysql to vb.net command

please help me on this code
when i run this code i having a error " invalid attempt to read when reader is close"
q = "select * from test.table1"
com = New MySqlCommand(q, con)
rs = com.ExecuteReader
While rs.Read
Dim ln = rs.GetInt64("id1")
Dim fn = rs.GetString("name")
If fn = TextBox1.Text Then
rs.Close()<this line having error>
f1 = "INSERT INTO test.table2(id2,fname,Mname,name)VALUE('" & "null" & "','" & TextBox2.Text & "','" & TextBox3.Text & "','" & Val(ln) & "')"
com = New MySqlCommand(f1, con)
com.ExecuteNonQuery()
End If
End While
con.Close()
rs.Dispose()
MsgBox("successfully inserted the data")
If you enter the if block you close the MySqlDataReader because you need to run an insert command, but when a connection is busy serving a DataReader cannot be used to serve another command. However the code continues and the next loop is executed. At this point if you try to read using the previous variable you get the error because the MySqlReader has been closed at the previous loop.
You could fix the problem opening a second connection using the connectionstring from the first connection. This seems to be the required path with MySql .NET Adapter because it doesn't support the MultipleActiveResultSets keyword in the connection string like SqlServer
While rs.Read
Dim ln = rs.GetInt64("id1")
Dim fn = rs.GetString("name")
If fn = TextBox1.Text Then
f1 = "INSERT INTO ........"
Using con2 = new MySqlConnection(con.ConnectionString)
con2.Open()
com = New MySqlCommand(f1, con2)
com.ExecuteNonQuery()
End Using
End If
End While

getting the id of record added to mysql db

Hoping someone can help me out with this.
I've made an app linked to a mysql db.
I'm writing details of remote hosts to a database at the minute.
I'm saving remote credentials too, but in a different table.
I have a colomn in my 'credentials' table called 'hosts_linked_id' which i want to contain the id of the parent record in the 'hosts' table.
Here is my code so far...
SQLConnection.ConnectionString = connectionstring
Try
If SQLConnection.State = ConnectionState.Closed Then
SQLConnection.Open()
Dim SQLStatement As String = "INSERT INTO hosts(name, description, host, type, port) VALUES('" & txtname.Text & "','" & txtdescription.Text & "','" & txthost.Text & "','" & cmbtype.Text & "','" & txtport.Text & "')"
SaveData(SQLStatement)
SQLConnection.Open()
SQLStatement = "INSERT INTO credentials(hosts_linked_id, username, password, type) VALUES('" & txtname.Text & "','" & txtusername.Text & "','" & encryptedpassword & "','" & cmbtype.Text & "')"
SaveData(SQLStatement)
Else
SQLConnection.Close()
End If
Also, here's the 'SaveData' function...
Public Sub SaveData(ByRef SQLStatement As String)
Dim cmd As MySqlCommand = New MySqlCommand
With cmd
.CommandText = SQLStatement
.CommandType = CommandType.Text
.Connection = SQLConnection
.ExecuteNonQuery()
End With
SQLConnection.Close()
MsgBox("Host has been added")
txtname.Text = ""
txtdescription.Text = ""
txthost.Text = ""
cmbtype.Text = ""
txtport.Text = ""
End Sub
What i need to do is get the id of the record created when my first 'INSERT' statement is executed into a variable so i can insert it into the 'credentials' table when my second 'INSERT' statement is executed.
I've googled the hell out of this and tried a few different methods, all without success.
Can anyone help point me in the right direction?
Thanks in advance!!
TL;DR: Need to get the ID of mysql record added when insert statement is executed and drop it into a variable