ExecuteNonQuery inside of Reader - vb.net

How can I solve this problem? I do not want to use two connections.
ExecuteNonQuery only works if reader is closed.
oleCnn = New System.Data.OleDb.OleDbConnection
oleCnn.ConnectionString = ConnectionString
oleCmm = New OleDb.OleDbCommand()
oleCnn.Open()
oleStr = "SELECT ID_Process FROM MyProcessTable"
Dim reader As System.Data.OleDb.OleDbDataReader = oleCmm.ExecuteReader()
While reader.Read()
For i = 1 To NumExecutions
oleStr = "INSERT INTO MyOtherProcessTable(reader.getInt32(0))"
oleCmm.ExecuteNonQuery()
Next
End While
reader.Close()
oleCnn.Close()
Thank you

Use a list to store your IDs while reading the DataReader, then for each element of the list you should be able to execute your query with then same connection:
oleCnn = New System.Data.OleDb.OleDbConnection
oleCnn.ConnectionString = ConnectionString
oleCmm = New OleDb.OleDbCommand()
oleCnn.Open()
oleStr = "SELECT ID_Process FROM MyProcessTable"
Dim ids As New List(Of Integer)
Dim reader As System.Data.OleDb.OleDbDataReader = oleCmm.ExecuteReader()
While reader.Read()
ids.Add(reader.GetInt32(0))
End While
reader.Close()
For Each curr_id As Integer In ids
For i = 1 To NumExecutions
oleStr = "INSERT INTO MyOtherProcessTable(" & curr_id.ToString & ")"
oleCmm.ExecuteNonQuery()
Next
Next
oleCnn.Close()
P.S. I don't understand the For i = 1 To NumExecutions for loop, but I added it as you wrote it

Related

Check if Row is already exist in table before inserting

Well its been a while since my last post about saving loops through checkboxlist.So I did manage to check the input before it saved into table, but somehow it couldnt save any data even if wasnt duplicate one.
Wanted to create a function to check if each checkboxlist is already present within the table but I cant manage it because it needs value from this script so I skip it.
Using conn2 As New SqlConnection()
conn2.ConnectionString = ConfigurationManager _
.ConnectionStrings("BackboneConnectionString").ConnectionString()
Using cmd As New SqlCommand
cmd.CommandText = "Insert into EL_MstFunctionalNilai values(#IDFunc, #nik, #IDFuncParent, #IDFuncChild, #IDFuncMtr, '', '', '0')"
cmd.Connection = conn2
conn2.Open()
For Each item As ListItem In CheckBoxList2.Items
If item.Selected Then
'cmd.Parameters.Clear()
Dim urutan As Int32 = GetNumberFunctional()
Dim str As String = item.Value.ToString
Dim strArr() As String = str.Split("_")
Dim IDFunctionalParent1 As String = strArr(0)
Dim IDFunctionalChild1 As String = strArr(1)
Dim IDFunctionalMtr1 As String = strArr(2)
cmd.CommandText = "select count(*)as numrows from el_mstFunctionalnilai where nik = #nik and idfuncmtr = #IDFuncMtr"
cmd.Parameters.AddWithValue("#nik", txtnik.Text)
cmd.Parameters.AddWithValue("#IDFuncMtr", IDFunctionalMtr1)
queryresult = cmd.ExecuteScalar()
If queryresult = 0 Then
cmd.Parameters.Clear()
cmd.Parameters.AddWithValue("#IDFunc", urutan)
cmd.Parameters.AddWithValue("#nik", txtnik.Text)
cmd.Parameters.AddWithValue("#IDFuncMtr", IDFunctionalMtr1) 'mtr
cmd.Parameters.AddWithValue("#IDFuncParent", IDFunctionalParent1) 'parent
cmd.Parameters.AddWithValue("#IDFuncChild", IDFunctionalChild1) 'child
cmd.ExecuteNonQuery()
'Label1.Text = queryresult --> already check if queryresult has value
End If
End If
Next
conn2.Close()
End Using
End Using
When its executed no error tho, so I cant figure it out what Im missing. Well how do I fix this up?
Thanks.
el_mstFunctionalnilai
EL_MstFunctionalNilai
Which is it? Be careful about capitalization.
I have guessed at all the SqlDbType Please check your database to get the actual types.
Code following your pattern with 2 hits to database.
Protected Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim queryResult As Integer
'Pass the connection string directly to the constructor of the connection
Using conn2 As New SqlConnection(ConfigurationManager.ConnectionStrings("BackboneConnectionString").ConnectionString())
'Pass the command text and the connection directly to the command constructor
'You do not need as alias for Count
Using cmd As New SqlCommand("select count(*) from EL_MstFunctionalNilai where nik = #nik and idfuncmtr = #IDFuncMtr", conn2)
conn2.Open()
'This value does not appear to change in the loop so I moved it outside the loop
Dim urutan As Int32 = GetNumberFunctional()
'Add the parameters outside of the loop and only change the value inside the loop
'The value of the text box can't change inside the loop so it can be assigned outside the loop
cmd.Parameters.Add("#nick", SqlDbType.Int).Value = CInt(txtnik.Text)
cmd.Parameters.Add("#IDFuncMtr", SqlDbType.VarChar)
Using cmd2 As New SqlCommand("Insert into EL_MstFunctionalNilai values(#IDFunc, #nik, #IDFuncParent, #IDFuncChild, #IDFuncMtr, '', '', '0')", conn2)
cmd2.Parameters.Add("#IDFunc", SqlDbType.Int).Value = urutan
cmd2.Parameters.Add("#nik", SqlDbType.Int).Value = CInt(txtnik.Text)
cmd2.Parameters.Add("#IDFuncMtr", SqlDbType.VarChar) 'mtr
cmd2.Parameters.Add("#IDFuncParent", SqlDbType.VarChar) 'parent
cmd2.Parameters.Add("#IDFuncChild", SqlDbType.VarChar) 'child
For Each item As ListItem In CheckBoxList2.Items
If item.Selected Then
Dim str As String = item.Value.ToString
Dim strArr() As String = str.Split("_"c)
Dim IDFunctionalParent1 As String = strArr(0)
Dim IDFunctionalChild1 As String = strArr(1)
Dim IDFunctionalMtr1 As String = strArr(2)
cmd.Parameters("#IDFuncMtr").Value = IDFunctionalMtr1
queryResult = CInt(cmd.ExecuteScalar())
If queryResult = 0 Then
cmd2.Parameters("#IDFuncMtr").Value = IDFunctionalMtr1 'mtr
cmd2.Parameters("#IDFuncParent").Value = IDFunctionalParent1 'parent
cmd2.Parameters("#IDFuncChild").Value = IDFunctionalChild1 'child
cmd.ExecuteNonQuery()
End If
End If
Next
End Using
End Using
End Using
End Sub
I think it would be easier using one query that both checks for the existence of the record and inserts it if it doesn't exist.
Protected Sub Method2()
Dim urutan As Int32 = GetNumberFunctional()
Using cn As New SqlConnection(ConfigurationManager.ConnectionStrings("BackboneConnectionString").ConnectionString())
Using cmd As New SqlCommand("If Exists (Select 1 From EL_MstFunctionalNilai where nik = #nik and idfuncmtr = #IDFuncMtr) Select 0 Else Select 1 Insert into EL_MstFunctionalNilai values(#IDFunc, #nik, #IDFuncParent, #IDFuncChild, #IDFuncMtr, '', '', '0');", cn)
cmd.Parameters.Add("#nik", SqlDbType.Int).Value = CInt(txtnik.Text)
cmd.Parameters.Add("#IDFuncMtr", SqlDbType.VarChar)
cmd.Parameters.Add("#IDFunc", SqlDbType.VarChar).Value = urutan
cmd.Parameters.Add("#IDFuncParent", SqlDbType.VarChar)
cmd.Parameters.Add("#IDFuncChild", SqlDbType.VarChar)
cn.Open()
For Each item As ListItem In CheckBoxList2.Items
If item.Selected Then
Dim strArr() As String = item.Value.ToString.Split("_"c)
cmd.Parameters("#IDFuncMtr").Value = strArr(2)
cmd.Parameters("#IDFuncParent").Value = strArr(0)
cmd.Parameters("#IDFuncChild").Value = strArr(1)
cmd.ExecuteScalar()
End If
Next
End Using
End Using
End Sub

vb.net Using SqlConnection doesn't free the file from use

I am working with a local .mdf file and I execute some queries to the database and I am using USING blocks to make sure the SqlConnection and SqlReader are disposed of correctly.
I then try to read the data of the file to generate a MD5 Hash of the file but it says the file is still in use.
The code isn't the cleanest it is my first time working with the Sql in a VB.NET app.
SQL Insert:
Dim finalW As String = ""
Dim finalO() As String
Dim currentcounter As Integer = 0
For Each Dir As String In System.IO.Directory.GetDirectories(Pathfinder)
Dim dirInfo As New System.IO.DirectoryInfo(Dir)
Dim temp As New List(Of String)
For Each currentFile In Directory.GetFiles(Pathfinder & "\" & dirInfo.Name & "\", "*.png", SearchOption.TopDirectoryOnly)
temp.Add(Path.GetFileName(currentFile))
Next
If temp.Count <> 0 Then
finalW = temp.Find(AddressOf GetNewIcon)
finalO = temp.FindAll(AddressOf GetOldIcon).ToArray
If finalW <> "" Then
Using con As New SqlClient.SqlConnection("Data Source=(LocalDB)\MSSQLLocalDB;AttachDbFilename=""" & PathFinal & "ImaginiDB.mdf"";Integrated Security=True")
con.Open()
Using cmd = con.CreateCommand()
cmd.CommandType = CommandType.Text
cmd.CommandText = "INSERT NewIcon (Name) VALUES ('" & finalW.Trim() & "')"
cmd.Connection = con
cmd.ExecuteNonQuery()
End Using
currentcounter = currentcounter + 1
Dim Id As String = ""
Using command = con.CreateCommand()
command.CommandType = CommandType.Text
command.CommandText = "SELECT * FROM NewIcon WHERE Name='" & finalW & "'"
Using reader As SqlDataReader = command.ExecuteReader()
While reader.Read()
Id = reader(0)
End While
End Using
End Using
For Each item As String In finalO
Using cmd2 = con.CreateCommand()
cmd2.CommandType = CommandType.Text
cmd2.CommandText = "INSERT OldIcon (NID,Name) VALUES ('" & Id & "','" & item.ToString.Trim() & "')"
cmd2.Connection = con
cmd2.ExecuteNonQuery()
End Using
currentcounter = currentcounter + 1
Next
Dim cur As Long = currentcounter * 100 / counter
SetProgress(cur)
End Using
End If
End If
Next
GC.Collect()
GC.WaitForPendingFinalizers()
SetLabel4Text("FINISHED IMPORT", Color.Red)
MD5 Generation ran after this process is finished:
Public Function GenMD5(ByVal Filename As String) As String
Dim MD5 = System.Security.Cryptography.MD5.Create
Dim Hash As Byte()
Dim sb As New System.Text.StringBuilder
Using st As New IO.FileStream(Filename, IO.FileMode.Open, IO.FileAccess.Read, IO.FileShare.Read)
Hash = MD5.ComputeHash(st)
End Using
For Each b In Hash
sb.Append(b.ToString("X2"))
Next
Return sb.ToString
End Function
So as mentioned in the comment by #jmcilhinney
Different connections use different pool as the MSDN says:
When a connection is first opened, a connection pool is created based
on an exact matching algorithm that associates the pool with the
connection string in the connection.
Thus I decided to implement the method:
SqlConnection.ClearPool(connection As SqlConnection)
I placed this just before my END USING:
Dim cur As Long = currentcounter * 100 / counter
SetProgress(cur)
SqlConnection.ClearPool(con)
End Using

Add Column to DataTable before exporting to Excel file

I have a DataTable that is built like this:
Dim dt As New DataTable()
dt = SqlHelper.ExecuteDataset(connString, "storedProcedure", Session("Member"), DBNull.Value, DBNull.Value).Tables(0)
Then it is converted to a DataView and exported to Excel like this:
Dim dv As New DataView()
dv = dt.DefaultView
Export.CreateExcelFile(dv, strFileName)
I want to add another column and fill it with data before I export to Excel. Here's what I'm doing now to add the column:
Dim dc As New DataColumn("New Column", Type.GetType("System.String"))
dc.DefaultValue = "N"
dt.Columns.Add(dc)
Then to populate it:
For Each row As DataRow In dt.Rows
Dim uID As Integer = Convert.ToInt32(dt.Columns(0).ColumnName)
Dim pID As String = dt.Columns(0).ColumnName
Dim qry As String = "SELECT * FROM [MyTable] WHERE [UserID] = " & uID & " AND [PassID] = '" & pID & "'"
Dim myCommand As SqlCommand
Dim myConn As SqlConnection = New SqlConnection(ConfigurationSettings.AppSettings("connString"))
myConn.Open()
myCommand = New SqlCommand(qry, myConn)
Dim reader As SqlDataReader = myCommand.ExecuteReader()
If reader.Read() Then
row.Item("New Column") = "Y"
Else
row.Item("New Column") = "N"
End If
Next row
But I get a "System.FormatException: Input string was not in a correct format." error when I run the app. It doesn't seem to like these lines:
Dim uID As Integer = Convert.ToInt32(dt.Columns(0).ColumnName)
Dim pID As String = dt.Columns(0).ColumnName
I think I have more than one issue here because even if I comment out the loop that fills the data in, the column I created doesn't show up in the Excel file. Any help would be much appreciated. Thanks!
EDIT:
Okay, I was grabbing the column name instead of the actual data in the column... because I'm an idiot. The new column still doesn't show up in the exported Excel file. Here's the updated code:
Dim dt As New DataTable()
dt = SqlHelper.ExecuteDataset(connString, "storedProcedure", Session("Member"), DBNull.Value, DBNull.Value).Tables(0)
Dim dc As New DataColumn("New Column", Type.GetType("System.String"))
dc.DefaultValue = "N"
dt.Columns.Add(dc)
'set the values of the new column based on info pulled from db
Dim myCommand As SqlCommand
Dim myConn As SqlConnection = New SqlConnection(ConfigurationSettings.AppSettings("connString"))
Dim reader As SqlDataReader
For Each row As DataRow In dt.Rows
Dim uID As Integer = Convert.ToInt32(row.Item(0))
Dim pID As String = row.Item(2).ToString
Dim qry As String = "SELECT * FROM [MyTable] WHERE [UserID] = " & uID & " AND [PassID] = '" & pID & "'"
myConn.Open()
myCommand = New SqlCommand(qry, myConn)
reader = myCommand.ExecuteReader()
If reader.Read() Then
row.Item("New Column") = "Y"
Else
row.Item("New Column") = "N"
End If
myConn.Close()
Next row
dt.AcceptChanges()
Dim dv As New DataView()
dv = dt.DefaultView
Export.CreateExcelFile(dv, strFileName)
I suppose that you want to search your MyTable if it contains a record with the uid and the pid for every row present in your dt table.
If this is your intent then your could write something like this
Dim qry As String = "SELECT UserID FROM [MyTable] WHERE [UserID] = #uid AND [PassID] = #pid"
Using myConn = New SqlConnection(ConfigurationSettings.AppSettings("connString"))
Using myCommand = new SqlCommand(qry, myConn)
myConn.Open()
myCommand.Parameters.Add("#uid", OleDbType.Integer)
myCommand.Parameters.Add("#pid", OleDbType.VarWChar)
For Each row As DataRow In dt.Rows
Dim uID As Integer = Convert.ToInt32(row(0))
Dim pID As String = row(1).ToString()
cmd.Parameters("#uid").Value = uID
cmd.Parameters("#pid").Value = pID
Dim result = myCommand.ExecuteScalar()
If result IsNot Nothing Then
row.Item("New Column") = "Y"
Else
row.Item("New Column") = "N"
End If
Next
End Using
End Using
Of course the exporting to Excel of the DataTable changed with the new column should be done AFTER the add of the column and this code that updates it
In this code the opening of the connection and the creation of the command is done before entering the loop over your rows. The parameterized query holds the new values extracted from your ROWS not from your column names and instead of a more expensive ExecuteReader, just use an ExecuteScalar. If the record is found the ExecuteScalar just returns the UserID instead of a full reader.
The issue was in my CreateExcelFile() method. I inherited the app I'm modifying and assumed the method dynamically read the data in the DataTable and built the spreadsheet. In reality, it was searching the DataTable for specific values and ignored everything else.
2 lines of code later, I'm done.

Populate ListBox from SQL only items with condition (first character)

I've managed to put all items in a ListBox, also have the first character defined kto, how to insert only those values from List column into Listbox that begin with that character kto.
Just to mention that kto is value from 0 to 9, always a number.
Dim SqlSb As New SqlConnectionStringBuilder()
SqlSb.DataSource = ".\sqlexpress"
SqlSb.InitialCatalog = "Konta"
SqlSb.IntegratedSecurity = True
Using SqlConn As SqlConnection = New SqlConnection(SqlSb.ConnectionString)
SqlConn.Open()
Dim cmd As SqlCommand = SqlConn.CreateCommand()
cmd.CommandText = "SELECT List FROM Konta"
Dim kto = Left(Label1.Text, 1)
'Label3.Text = kto
Using reader As SqlDataReader = cmd.ExecuteReader
While (reader.Read())
Me.ListBox1.Items.Add(reader("LIST"))
End While
End Using
SqlConn.Close()
End Using
Try this
Dim SqlSb As New SqlConnectionStringBuilder()
SqlSb.DataSource = ".\sqlexpress"
SqlSb.InitialCatalog = "Konta"
SqlSb.IntegratedSecurity = True
Using SqlConn As SqlConnection = New SqlConnection(SqlSb.ConnectionString)
SqlConn.Open()
Dim cmd As SqlCommand = SqlConn.CreateCommand()
Dim kto = Left(Label1.Text, 1)
cmd.CommandText = "SELECT List FROM Konta WHERE List LIKE '" & kto.toString & "%'"
ListBox1.Items.Clear
Using reader As SqlDataReader = cmd.ExecuteReader
While (reader.Read())
Me.ListBox1.Items.Add(reader("LIST"))
End While
End Using
SqlConn.Close()
End Using
In your while loop, before adding the item in the listbox check the date type of reader("LIST") and add it only if matches the required type.
You can check the type using the following code:
reader.GetFieldType(0)

Not able read the next record using datareader

I want to retrieve data from multiple tables and want to generate a crystal report. Hence i have created a new table and inserting values in it each time i need to generate the report. So i am using the following code to retrieve the data from those tables.
Code:
Private Sub gen_Report()
Dim dr, dr1, dr2 As OleDb.OleDbDataReader
Dim cmd, cmdDel, comm_inv1, comm_invuser As OleDb.OleDbCommand
If cnnOLEDB.State = ConnectionState.Closed Then
cnnOLEDB.Open()
End If
Dim strDelInsRp As String = ("DELETE FROM Inst_Report")
cmdDel = New OleDb.OleDbCommand(strDelInsRp, cnnOLEDB)
cmdDel.Parameters.AddWithValue("#chlno", cmbChal_no.Text)
cmdDel.ExecuteNonQuery()
Dim strSelIns As String = ("SELECT * FROM Installation_det where Chalan_No=#chlno")
cmd = New OleDb.OleDbCommand(strSelIns, cnnOLEDB)
cmd.Parameters.AddWithValue("#chlno", cmbChal_no.Text)
dr = cmd.ExecuteReader
Try
Do While dr.Read = True
mach_srno = dr("Machine_SrNo")
tft_srno = dr("TFT_SrNo")
chl_no = dr("Chalan_No")
usernm = dr("User_Name")
ins_dt = dr("Date_Of_Installation")
war_perd = dr("Warranty_Period")
war_till = dr("Warranty_Valid_Till")
Dim strSelInv1 As String = ("SELECT * FROM INVOICE_ONE where LAY_NO='VDC' AND CHL_NO=#chn_no ")
comm_inv1 = New OleDb.OleDbCommand(strSelInv1, cnnOLEDB)
comm_inv1.Parameters.AddWithValue("#chn_no", chl_no)
dr1 = comm_inv1.ExecuteReader
If dr1.Read = True Then
doc_no = dr1("DOCU_NO")
code_no = dr1("CODE_NO")
memb_nm = dr1("MEMB_NM")
Dim strSelInvUser As String = ("SELECT * FROM INVOICE_USER where CODE_NO=#code AND LAY_NO='VDC' AND DOCU_NO=#docno")
comm_invuser = New OleDb.OleDbCommand(strSelInvUser, cnnOLEDB)
comm_invuser.Parameters.AddWithValue("#code", code_no)
comm_invuser.Parameters.AddWithValue("#docno", doc_no)
dr2 = comm_invuser.ExecuteReader
If dr2.Read = True Then
User_add = dr2("ILEN2") & dr2("ILEN3") & dr2("ILEN4") & dr2("ILEN5")
End If
dr2.Close()
End If
dr1.Close()
Dim strInsRep As String = "INSERT INTO Inst_Report(Mach_srNo,TFT_srNo,Mem_nm,UserNm,Dt_Inst,War_Per,war_till,User_Address) VALUES (#mach_srno,#tft_no,#mem_nm,#uname,#inst_dt,#war_per,#war_till,#address)"
Dim comm_InsRep As OleDb.OleDbCommand = New OleDb.OleDbCommand(strInsRep, cnnOLEDB)
comm_InsRep.Parameters.AddWithValue("#mach_srno", mach_srno)
comm_InsRep.Parameters.AddWithValue("#tft_no", tft_srno)
comm_InsRep.Parameters.AddWithValue("#mem_nm", memb_nm)
comm_InsRep.Parameters.AddWithValue("#uname", usernm)
comm_InsRep.Parameters.AddWithValue("#inst_dt", ins_dt)
comm_InsRep.Parameters.AddWithValue("#war_per", war_perd)
comm_InsRep.Parameters.AddWithValue("#war_till", war_till)
comm_InsRep.Parameters.AddWithValue("#address", User_add)
comm_InsRep.ExecuteNonQuery()
Loop
dr.Close()
Catch ex As Exception
MsgBox(ex.Message)
End Try
End Sub
But the problem is that the datareader only reads for the first record even if I am using 'do While Loop'.
I have another question:
As the number of fields are more I want to generate report in Landscape orientation.
So how to change the orientation of report.
I am using Visual studio 2005 and MS-Access 2007. And programming language is VB.NET.
Regarding your data, I believe the standard way to get data from an OleDbDataReader is to use it to fill a datatable, try this:
Private Function GetDataTableUsingDataReader(ByVal command As OleDbCommand) As DataTable
Dim dataTable As DataTable = New DataTable
Using reader As OleDbDataReader = command.ExecuteReader
dataTable.Load(reader, LoadOption.OverwriteChanges)
End Using
Return dataTable
End Function
To get your crystal report to landscape, right click on the report in the designer, goto design => page setup. From here you can change the orientation.