Am I loading datatable twice & update row item with boolean value - vb.net

I call the following function in a module
Public Function GetExcelData(ByVal ExcelFile As String) As System.Data.DataTable
Then I have the following code
If openFileDialog1.ShowDialog() = System.Windows.Forms.DialogResult.OK Then
gblCompName = openFileDialog1.FileName
End If
Dim reader As New DataTableReader(GetExcelData(gblCompName))
Dim table As New DataTable
table.Load(reader)
table.Columns.Add("Single", GetType(Boolean), False)
table.Columns.Add("CouplesInFinal", GetType(Int32))
table.Columns.Add("EvtNum", GetType(String))
table.Columns.Add("EvtStruct", GetType(Int32))
table.Columns.Add("EvtCplID", GetType(Int32))
table.Columns.Add("CouplesInClass", GetType(Int32))
table.Columns.Add("Valid", GetType(Boolean), True)
Dim result() As DataRow = table.Select("[class]" Like "Single")
For Each row In result
If row.Item("Class") Like "Single" Then
table.Rows(0)("Single") = True
End If
Next
DataGridView1.DataSource = table
My logic tells me I'm loading the table twice & the data row field "Single" is boolean which I'm trying to update to True if string field "class" is like "Single"
I realize it's 2 questions in one but it seems to load quite slowly & it's all one form procedure. Any advice on this will be very welcome thanks

Dim reader As New DataTableReader(GetExcelData(gblCompName))
Dim table As New DataTable
Without seeing GetExcelData it is hard to say if you are filling twice. If this function returns a populated DataTable then
Dim table as DataTable = GetExcelData(gblCompName)
and delete the table.Load and the DataReader.
Here is my version of updating a DataTable against my sample database.
Private Sub TestDataTableUpdate()
Try
Using cmd As New SqlCommand("Select * From Coffees", CoffeeCn)
Dim dt As New DataTable
CoffeeCn.Open()
Using dr As SqlDataReader = cmd.ExecuteReader
dt.Load(dr)
End Using
CoffeeCn.Close()
For index As Integer = 0 To dt.Rows.Count - 1
If dt.Rows(index)("Name").ToString = "Cinnamon Stick" Then
dt.Rows(index)("Roast") = "N/A"
End If
Next
'The above does not update the database
Dim da As New SqlDataAdapter(cmd) 'provides the connection and Select command
Dim sqlCB As New SqlCommandBuilder(da) 'Associates the DataAdapter to the command builder
sqlCB.GetUpdateCommand() 'Retrieve the update command for the DataAdapter
'Note: the DataAdapter opens and closes the connection for you
da.Update(dt) 'This updates the database by finding the changed rows in the datatable
'and running the Update command
dt.AcceptChanges() 'Reset the row status to unchanged
DataGridView1.DataSource = dt
End Using
Catch ex As Exception
MessageBox.Show(ex.Message)
Finally
CoffeeCn.Close()
End Try
End Sub
PS. I am self-taught also.

The table update method that I got to work is
Dim i As Integer = 0
For i = 0 To table.Rows.Count - 1
If table.Rows(i)("Class") Like "*Single*" Then
table.Rows(i)("Single") = True
End If
Next
I took out the ",False" on this line table.Columns.Add("Single", GetType(Boolean)

Related

Double click datagrid and paste to database record

I want to double click a row in my datagrid and to transfer that data to my database, which then goes on to open a report based on that data just transferred.
If e.RowIndex >= 0 AndAlso e.ColumnIndex >= 0 Then
Dim selectedRow = DataGridView1.Rows(e.RowIndex)
End If
'Dim PtwNoData As String = String.Empty
Dim connection As SqlConnection
Dim Command As SqlCommand
Dim dt As New DataTable
Dim IdLast As Integer
Dim PTWNo As String
Dim Reader As SqlDataReader
connection = New SqlConnection("Data Source=(LocalDB)\MSSQLLocalDB;AttachDbFilename=C:\Users\IzzyM\Desktop\Developer\BIG\Permit Plus\Permit Plus\Database1.mdf;Integrated Security=True")
Dim GuiD As String
'GuiD = Me.DataGridView1.SelectedRows("GUID").Selected.
Try
connection.Open()
Dim Query As String
Query = "insert into PTWData * values ('" & Me.DataGridView1.SelectedRows(). & "')"
Command = New SqlCommand(Query, connection)
Reader = Command.ExecuteReader
connection.Close()
Catch ex As Exception
MessageBox.Show(ex.Message)
Finally
connection.Dispose()
End Try
'Form4.Dispose()
Dim f As New Form4()
f.TopMost = True
f.Show()
'Form4.Show()
End Sub```
You're wanting to add string values there, but the selected rows is a complicated object. It contains the resulting rows and each column within (along with many, many properties).
See below, where "ColumnNameIDK" is only one and you may have many to consider. This query will ultimately be a lot of inserts. (For safety sake, we may want to convert this to a parameterized query down the road)
...
Dim Query As String
Dim rows As DataGridViewSelectedRowCollection = MyDataGridView.SelectedRows
for each row in Me.DataGridView1.SelectedRows()
Dim myRow As DataRow = (TryCast(row.DataBoundItem, DataRowView)).Row
query &= "insert into PTWData * values ('" & myRow("ColumnNameIDK")& "');"
'this query appended on each pass
next
Command = New SqlCommand(Query, connection)
Reader = Command.ExecuteReader

VB.Net Parameter count mismatch

I'm writing a function that convert an Array List into a Data Table, and I'm getting an error "Parameter count mismatch".
I've been looking and googling the issue but couldn't found anything that could help me resolve my issue.
```
'Function that convert ArrayList to DataTable
Public Function ConvertArrayListToDataTable(ByVal MyAList As ArrayList) As DataTable
Dim dt As New DataTable()
For i As Integer = 0 To MyAList.Count - 1
'create a Generic Object
Dim values As Object = MyAList.Item(i)
Dim properties() As PropertyInfo =
values.GetType().GetProperties()
'Loop through each property, and add it as a column to the datatable
For Each prop As PropertyInfo In properties
Try
Dim dc As DataColumn = New DataColumn(prop.Name)
'Add the column definition to the datatable
dc.DataType = prop.PropertyType
dt.Columns.Add(dc)
Catch ex As Exception
MessageBox.Show(" Can't add column" & ex.Message)
End Try
Next
'for each object in the list, loop through and add
'the data to the database
For Each o As Object In MyAList
Try
'create new row
Dim row As DataRow = dt.NewRow()
Dim pf() As PropertyInfo = o.GetType().GetProperties()
For Each item As PropertyInfo In pf
row(item.Name) = item.GetValue(o, Nothing)
Next
dt.Rows.Add(row)
Catch ex As Exception
MessageBox.Show(" Conversionerror" & ex.Message)
End Try
Next
Next
Return dt
End Function
```
I see the code get the Table and the column count as well, but cannot write value. it failed on getvalue.
The function suppose return a datatable containing retrieved data and populate datagrid
For Each prop As PropertyInfo In properties
Try
Dim dc As DataColumn = New DataColumn(prop.Name)
dc.DataType = prop.PropertyType
dt.Columns.Add(dc)
Catch ex As Exception
MessageBox.Show(" Can't add column" & ex.Message)
End Try
Next
If you are filling a DataTable from a database just let the DataTable figure out the datatype. ArrayList is not used in new code. You can make a class or structure and then use List(Of T) or if absolutely necessary List(Of Object). Test just the plain old DataTable.
Private Sub FillDataGridView()
Dim dt = New DataTable()
Using cn As New SqlConnection(My.Settings.CoffeeConnection)
Using cmd As New SqlCommand("Select * From Coffees;", cn)
cn.Open()
dt.Load(cmd.ExecuteReader)
End Using
End Using
For Each col As DataColumn In dt.Columns
Debug.Print(col.DataType.Name)
Next
DataGridView1.DataSource = dt
End Sub
Thank you Mary. It was a great experience. I was challenging myself to see how I can fill the Datagrid from Arraylist to Datatable. I finally follow your advice and review my Function as below:
Public Function FillDataGridView(SQLStatement As String) As DataTable
'create an DataTable to hold the results
Dim dt As New DataTable()
Try
Using con As New SqlConnection(ConnectionString)
con.Open()
Using cmd As New SqlCommand(SQLStatement, con)
'Get the reader
Using Reader = cmd.ExecuteReader()
dt.Load(Reader)
End Using
End Using
End Using
For Each col As DataColumn In dt.Columns
Debug.Print(col.DataType.Name)
Next
Catch ex As Exception
Console.WriteLine("SQL retrieve row:" & ex.Message & Err.Number)
Finally
Call CloseConn()
End Try
Return dt
End Function

How do I create a dataset in VB.NET from this code?

I currently have the following code in my project which populates a DataGridView object with the results of an SQL query.
Sub PerformQuery(ByVal SQLText As String)
Dim DbConnection As New OleDb.OleDbConnection(createConnectionString)
Dim SQLQuery As String = SQLText
Dim Adapter As New OleDb.OleDbDataAdapter(SQLQuery, DbConnection)
Try
Using Table As New DataTable
Adapter.Fill(Table)
Table.Locale = Globalization.CultureInfo.InvariantCulture
DbConnection.Close()
DataGridView1.DataSource = Table
End Using
Catch ex As Exception
MsgBox(ex.Message)
End Try
End Sub
Elsewhere in my project I can create a DataSet object using the code
Dim ds As New DataSet
And then extract data from it using code like:
MaxRows = ds.Tables("Dataset_Users").Rows.Count
Rather than populating a DataGridView, how can I use the PerformQuery code to create a dataset?
Thank you in advance for your help.
I think you are after the following:
Try
Dim ds As New DataSet
Using Table As New DataTable
Adapter.Fill(Table)
Table.Locale = Globalization.CultureInfo.InvariantCulture
DbConnection.Close()
DataGridView1.DataSource = Table
ds.Table.Add(Table)
End Using
Catch ex As Exception
MsgBox(ex.Message)
End Try
Or as in your example you was after the Number of rows in the dataset you can do the same with the DataTable, For Example:
Try
Dim MaxRows As Integer
Using Table As New DataTable
Adapter.Fill(Table)
Table.Locale = Globalization.CultureInfo.InvariantCulture
DbConnection.Close()
DataGridView1.DataSource = Table
'' Getting the number of rows in the DataTable
MaxRows = Table.Rows.Count
End Using
Catch ex As Exception
MsgBox(ex.Message)
End Try
Think in a more functional style. Return the table instead of setting to grid. While we're here, let's update the method so you don't have to write queries anymore that leave you wide open to sql injection attacks:
Function PerformQuery(ByVal SQLText As String, ByVal ParamArray Parameters() As OleDbParameter) As DataTable
Dim result As New DataTable()
Using cn As New OleDb.OleDbConnection(createConnectionString), _
cmd As New OleDb.OleDbCommand(SQLText, cn), _
Adapter As New OleDb.OleDbDataAdapter(cmd, cn)
If Parameters IsNot Nothing AndAlso Parameters.Length > 0 Then
cmd.Parameters.AddRange(Parameters)
End If
Adapter.Fill(result)
End Using
Return Result
End Function
Note that I also removed the error handling and locale code. You still need to do that stuff, but when you want to just return a datatable instead of interact directly with the user interface in a method you have effectively moved your code to a lower level of abstraction. When you do that, you probably don't want to deal with the error handling at this lower level any more; instead let the exceptions bubble up where you can handle them closer to the user interface.
Now you call the updated method like this:
Dim sql As String = "SELECT * FROM Customers WHERE CustomerID = ?"
Dim CustID As New OleDb.OleDbParameter("CustomerId", OleDbType.Integer)
CustID.Value = 123456
Try
DataGridView1.DataSource = PerformQuery(sql, CustID)
Catch Ex As Excpetion
MsgBox(Ex.Message)
End Try

Loop through action

I am new to visual basic, however I need to loop through rows in a data table and use the values to in a test script, the script is as follows -
Public Function TestMain(ByVal args() As Object) As Object
StartApp(URL)
' HTML Browser '
Browser_HtmlBrowser(Document_HomePage(),DEFAULT_FLAGS).Maximize()
Button_AddNewProfilesubmit().Click()
'here is where the rows would be read and the loop would start'
Text_Ctl00MainContentProfileNa().Click(AtPoint(6, 13))
Browser_HtmlBrowser(Document_Http1921685526UserCon(), DEFAULT_FLAGS).InputChars("dataBase_Row_Value")
Table_HtmlTable_1().Click(AtCell( _
AtRow(AtIndex(0)), _
AtColumn(AtIndex(1))))
'here is where the loop would end after all rows had been read'
Return Nothing
End Function
I have an idea to achieve this, first doing a database connection, then create the loop -
Dim pName As String
Dim datas As DataSet
Dim datar As DataRow
Dim oledat As SqlDataAdapter
oledat = New SqlDataAdapter("SELECT COLUMN FROM DATABASE",ConnectionString)
oledat.Fill(datas)
For Each datar In datas.Tables(0).Rows
pName = datar.Item("PROFILENAME")
Text_Ctl00MainContentProfileNa().Click(AtPoint(6, 13))
Browser_HtmlBrowser(Document_Http1921685526UserCon(), DEFAULT_FLAGS).InputChars(pName)
Table_HtmlTable_1().Click(AtCell( _
AtRow(AtIndex(0)), _
AtColumn(AtIndex(1))))
Next
However this is breaking, even though there are no errors in Visual Studio, there is only the warning that datas is used before it is assigned the values. Where am I going wrong?
I believe you must initialize a new dataset before working with it. Example:
Dim ds As DataSet = New DataSet()
Dim connection As OleDb.OleDbConnection
Dim command As OleDb.OleDbCommand
Dim adapter As New OleDb.OleDbDataAdapter
Dim connString As String = "my Connection string stuff;"
connection = New OleDb.OleDbConnection(connString)
Try
'open the connection
If connection.State = ConnectionState.Open Then
Else
connection.Open()
End If
'fill each data table
command = New OleDb.OleDbCommand(selectOne, connection)
adapter.SelectCommand = command
adapter.Fill(ds, "someTableName")
Catch ex As OleDb.OleDbException
'error, do something
Finally
'close everything down
adapter.Dispose()
If (Not command Is Nothing) Then
command.Dispose()
End If
connection.Close()
End Try
This example uses OLEDB but should be comparable to what you are doing. Once you fill it, you should be able to iterate over the tables. But, first, check to make sure you have a dataset created first:
If (ds IsNot Nothing) Then
'do for statement here
End If
If this does not work, let me know.

Better way to print out rows from a datatable in vb.net

I am new to vb.net and I am trying to query a database and print out the records in the row to the console window. I got it to work, but I have a feeling that there is a more concise way to do this. One thing that I am sure is wrong is that I had to convert the dataset to a datatable to be able to retrieve the values. Is that correct? Could you take a look at the code below (especially the for loop) and let me know what I can improve upon?
Thanks!
Module Module1
Sub Main()
Dim constring As String = "Data Source=C:\Users\test\Desktop\MyDatabase1.sdf"
Dim conn As New SqlCeConnection(constring)
Dim cmd As New SqlCeCommand("SELECT * FROM ACCOUNT")
Dim adapter As New SqlCeDataAdapter
Dim ds As New DataSet()
Try
conn.Open()
cmd.Connection = conn
adapter.SelectCommand = cmd
adapter.Fill(ds, "testds")
cmd.Dispose()
adapter.Dispose()
conn.Close()
Dim dt As DataTable = ds.Tables.Item("testds")
Dim row As DataRow
Dim count As Integer = dt.Columns.Count()
For Each row In dt.Rows
Dim i As Integer = 0
While i <= count - 1
Console.Write(row(i))
i += 1
End While
Console.WriteLine(Environment.NewLine())
Next
Catch ex As Exception
Console.WriteLine("There was an error")
Console.WriteLine(ex)
End Try
Console.ReadLine()
End Sub
End Module
Here is how I would rewrite this for a few reasons:
1) You should always use Using statements with disposable objects to ensure they are correctly cleaned up. You had a good start with the dispose commands, but this way is safer.
2) It is more efficient to use ExecuteReader than loading everything into a dataset.
3) Your try/catch statement should include object creation as well as execution.
Finally, in response to your question about datasets and datatables, that code was absolutely correct: a dataset consists of zero or more datatables, so you were just extracting the existing datatable from the dataset.
Try
Dim constring As String = "Data Source=C:\Users\test\Desktop\MyDatabase1.sdf"
Using conn As New SqlCeConnection(constring)
conn.Open()
Using cmd As New SqlCeCommand("SELECT * FROM ACCOUNT", conn)
Dim reader As SqlCeDataReader
reader = cmd.ExecuteReader()
Do While reader.Read
For i As Integer = 0 To reader.FieldCount - 1
Console.Write(reader.GetString(i))
Next
Console.WriteLine(Environment.NewLine())
Loop
End Using
End Using
Catch ex As Exception
Console.WriteLine("There was an error")
Console.WriteLine(ex)
End Try
Console.ReadLine()
End Sub
One last note: since you are just printing to the console, it doesn't matter as much, but whenever you deal with a lot of strings, especially those that are to be concatenated, you should always consider using System.Text.StringBuilder.
Here is an example rewrite of the loop that prints to the console using stringbuilder (builds the string in memory, then dumps it to the console; I have also added the field name for good measure):
Dim sbOutput As New System.Text.StringBuilder(500)
For i As Integer = 0 To reader.FieldCount - 1
If sbOutput.Length <> 0 Then
sbOutput.Append("; ")
End If
sbOutput.Append(reader.GetName(i)).Append("=").Append(reader.GetString(i))
Next
sbOutput.AppendLine()
Console.Write(sbOutput.ToString)