Conversion error in vb.net? - vb.net

I am puzzled by why it does not retrieve the data and keep saying i have a error "InvalidCastException", i am currently doing these in compact framework and is totally new to it, i searched around looking for a way to get data into a listview base on what little i know about java .
these are my creation of table and inserting during formload
Dim createTable3 As SqlCeCommand = connection.CreateCommand
createTable3.CommandText = "CREATE TABLE product(product_id int IDENTITY(0,1) PRIMARY KEY,product_name nvarchar(50),bought_price float,sales_price float)"
connection.Open()
createTable3.ExecuteNonQuery()
Dim insertCmd2 As SqlCeCommand = connection.CreateCommand
insertCmd2.CommandText = "INSERT INTO product(product_name,bought_price)Values('Food',1.00)"
insertCmd2.ExecuteNonQuery()
Dim insertCmd3 As SqlCeCommand = connection.CreateCommand
insertCmd3.CommandText = "INSERT INTO product(product_name,bought_price)Values('Orange',1.50)"
insertCmd3.ExecuteNonQuery()
Dim insertCmd4 As SqlCeCommand = connection.CreateCommand
insertCmd4.CommandText = "INSERT INTO product(product_name,bought_price)Values('Apple',3.00)"
insertCmd4.ExecuteNonQuery()
Dim insertCmd5 As SqlCeCommand = connection.CreateCommand
insertCmd5.CommandText = "INSERT INTO product(product_name,bought_price)Values('Fruit',2.00)"
insertCmd5.ExecuteNonQuery()
connection.Close()
this is a code for a get info button
Dim itmListItem As ListViewItem
Dim shtFieldCntr As Short
Dim loopCmd As SqlCeCommand = connection.CreateCommand
loopCmd.CommandText = "SELECT * FROM product"
connection.Open()
Dim dr As SqlCeDataReader = loopCmd.ExecuteReader
Do While dr.Read
itmListItem = New ListViewItem()
If dr.IsDBNull(dr(0)) Then
itmListItem.Text = ""
Else
itmListItem.Text = dr(0)
End If
For shtFieldCntr = 1 To dr.FieldCount()
If dr.IsDBNull(shtFieldCntr) Then
itmListItem.SubItems.Add("")
Else
itmListItem.SubItems.Add(dr.GetString(shtFieldCntr)) ' error this line
End If
Next shtFieldCntr
lvProduct.Items.Add(itmListItem)
Loop
connection.Close()
picture

If you review the documentation for SqlCeDataReader.GetString, it mentions under "Remarks" that:
No conversions are performed;
therefore, the data retrieved must
already be a string.
This will be why you're getting an InvalidCastException. None of your fields, except for product_name, are strings. What you need to do is something like:
itmListItem.SubItems.Add(Convert.ToString(dr.GetValue(shtFieldCntr)))
When you know what all the fields in a table are, it would make more sense to call them and then add them to SubItems explicitly i.e:
Dim productId As Int32 = dr.GetInt32(dr.GetOrdinal("product_id"))
Dim productName As String = dr.GetString(dr.GetOrdinal("product_name"))
itmListItems.SubItems.Add(productId)
itmListItems.SubItems.Add(productName)

Related

vb.net Loading Images from Access Database to DataTable?

So I have a MS Access Database with 1 table (Records) and 2 fields in it ("RecordID" (Number), which is the primary key, and "LowRes" (OLE Object) which is a low Resolution image). There are about 100 records.
I/m trying to load the Access Table into a DataTable (ID_Table) in VB.net.
Code so far:
Dim cnString As String = "Provider=Microsoft.ACE.OLEDB.12.0; Data Source=SBS2257_ID.accdb;"
Dim theQuery As String = "SELECT [RecordID], [LowRes] FROM [Records];"
Using CN As New OleDbConnection(cnString)
Dim command As New OleDbCommand(theQuery, CN)
Using objDataAdapter = New OleDbDataAdapter(command)
Dim ID_Table As New DataTable
CN.Open()
Dim pictureData As Byte() = DirectCast(command.ExecuteScalar(), Byte())
Dim picture As Image = Nothing
Using stream As New IO.MemoryStream(pictureData)
picture = Image.FromStream(stream)
objDataAdapter.Fill(ID_Table)
End Using
End Using
End Using
However the "DirectCast" command fails when I tell it to look at more then 1 field in my SQL statement with a datatype mismatch (if I just do [LowRes] it does not throw a error). However, I get stuck again when trying to apply the result to the table via the objDataAdapter, it doesnt fill the table with anything? I also notice that "picture" only contains the first image in the database.
I could put this database query in a function using "WHERE RECORDID=..." and loop it manually building the table returning "picture" each time, but Id like to avoid running a function 100 times, esp one that access a database.
Is it possible to read the whole database that contains images and just load it directly into a Datatable in one big swoop?
EDIT: So I got this to work:
Dim strConnection As String = "Provider=Microsoft.ACE.OLEDB.12.0; Data Source=SBS2257_ID.accdb;"
Dim strSQL As String = "SELECT [RecordID], [LowRes] FROM [Records];"
Using objConnection = New OleDbConnection(strConnection)
Using objCommand = New OleDbCommand(strSQL, objConnection)
Using objDataAdapter = New OleDbDataAdapter(objCommand)
Dim objDataTable As New DataTable("IDs")
objDataAdapter.Fill(objDataTable)
Return objDataTable
End Using
End Using
End Using
how ever when I go to view row 0, col 1 which should be the first LowRes image via a .ToString Useing this code:
Private Sub PrintValues(ByVal table As DataTable)
For Each row As DataRow In table.Rows
For Each col As DataColumn In table.Columns
MsgBox(row(col).ToString())
Next col
Next row
End Sub
It just displays "System.Byte[]". It knows its a Byte datatype, but how do I display that in a picturebox?
The ExecuteScalar() executes the query, and returns the first column of the first row in the result set returned by the query.
as your query is
Dim theQuery As String = "SELECT [RecordID], [LowRes] FROM [Records];"
the first column is RecordID which is not a Byte().
you can change your query as following:
Dim theQuery As String = "SELECT [LowRes] FROM [Records];"
or you have to use other methods to get data from the database
Dim strSql As String = "SELECT [RecordID], [LowRes] FROM [Records]"
Dim dtb As New DataTable
Using cnn As New OleDbConnection(connectionString)
cnn.Open()
Using dad As New OleDbDataAdapter(strSql, cnn)
dad.Fill(dtb)
End Using
cnn.Close()
End Using

Looping through tables and querying each one which has TRelationcode in it

I'm having trouble with code that loops through the tables that contain TRelationCode. When it finds one it has to get the RelationCode from it and then convert it into the new RelationCode and update it to the new one.
To create the new RelationCode I've made a function Called MakeRelationCode(OldRelation). I have this code to loop through the tables:
Dim query As String = "use fmsStage; SELECT * FROM INFORMATION_SCHEMA.columns WHERE COLUMN_NAME = 'TRelationcode'"
Dim myCmd As SqlDataAdapter = New SqlDataAdapter(query, con)
Dim myData As New DataSet()
myCmd.Fill(myData)
For Each table As DataTable In myData.Tables
For Each row As DataRow In table.Rows
For Each col As DataColumn In table.Columns
Next
Next
Next
But now I need to update the old codes to the new ones.
I prefer simple SQL commands and a little vb logic thus I skipped the SqlDataAdapter part. This will only cost performance and is only necessary if you display something in a grid and want two-way-binding.
The following code is untested and typed blind so please check for typos etc.
I put everything in one method.
Dim tableNames As New List(Of String)
'Key: Old code, Value: New code'
Dim trelationcodes As New Dictionary(Of String, String)
Using conn As New SqlClient.SqlConnection("YourConnectionString") 'Change connection string to your needs'
Dim qTableNames = "SELECT TABLE_NAME FROM INFORMATION_SCHEMA.columns WHERE COLUMN_NAME = 'TRelationcode'"
conn.Open()
'Get table names with TRelationcode column'
Using commTableNames As New SqlClient.SqlCommand(qTableNames, conn)
Dim dataReader = commTableNames.ExecuteReader()
While dataReader.Read()
tableNames.Add(dataReader.GetString(0))
End While
End Using
'Select all distinct old TRelationcode which will be updated'
Dim qTrelationcodesOld = "SELECT DISTINCT TRelationcode FROM {0}"
For Each tableName In tableNames
'Get all old TRelationcodes from table found previuosly'
Using commTrelationcodesOld As New SqlClient.SqlCommand()
commTrelationcodesOld.Connection = conn
commTrelationcodesOld.CommandText = String.Format(qTrelationcodesOld, tableName)
Dim dataReader = commTrelationcodesOld.ExecuteReader()
While dataReader.Read()
Dim code = dataReader.GetString(0)
If Not trelationcodes.ContainsKey(code) Then
trelationcodes.Add(code, "") 'Value will be set later'
End If
End While
End Using
'Get new TRelationcodes'
For Each tRelCodeOld In trelationcodes.Keys
trelationcodes(tRelCodeOld) = MakeRelationCode(tRelCodeOld)
Next
'Set new TRelationcodes'
Dim uTRelationcode = "UPDATE {0} SET TRelationcode = #newCode WHERE TRelationcode = #oldCode"
For Each tRelCodes In trelationcodes
Using commTrelationcodesNew As New SqlClient.SqlCommand()
commTrelationcodesNew.Connection = conn
commTrelationcodesNew.CommandText = String.Format(uTRelationcode, tableName)
commTrelationcodesNew.Parameters.Add("#oldCode", SqlDbType.VarChar).Value = tRelCodes.Key 'Varchar correct?'
commTrelationcodesNew.Parameters.Add("#newCode", SqlDbType.VarChar).Value = tRelCodes.Value 'Varchar correct?'
commTrelationcodesNew.ExecuteNonQuery()
End Using
Next
Next
End Using
The code is far away from being optimal, e.g. I skipped exception handling.
The most concerning part is your MakeRelationCode function. If the logic inside could be written in T-SQL in a Stored Procedure, the overall coding would also be simplified.

Error Adding Data to Access Database

I am trying to add a new record to an Access database. I am new to Visual Basic but have been searching for an answer to this. Here is my code so far:
Dim ID As Integer = CInt(IDBox.Text)
Dim password As Integer = CInt(PasswordBox.Text)
Dim first As String = FirstName.Text
Dim last As String = LastName.Text
Dim access As Integer = CInt(AccessLevel.Text)
Dim conn As New OleDbConnection("Provider = Microsoft.ACE.OLEDB.12.0;Data Source=C:\Users\Tristan\Documents\Visual Studio 2015\Projects\Keno\Keno\Users.accdb")
conn.Open()
Dim ds As New DataSet
Dim da As OleDb.OleDbDataAdapter
da = New OleDb.OleDbDataAdapter("SELECT * FROM Users", conn)
da.Fill(ds, "Users")
Dim cb As New OleDbCommandBuilder(da)
Dim dsNewRow As DataRow
dsNewRow = ds.Tables("Users").NewRow()
dsNewRow.Item("ID") = ID
dsNewRow.Item("First_Name") = first
dsNewRow.Item("Last_Name") = last
dsNewRow.Item("Password") = password
dsNewRow.Item("Access_Level") = access
ds.Tables("Users").Rows.Add(dsNewRow)
cb.GetInsertCommand()
da.Update(ds, "Users")
conn.Close()
MsgBox("User added successfully!")
Running this gets an error:
An unhandled exception of type System.Data.OleDb.OleDbException
occurred in System.Data.dll
Additional information: Syntax error in INSERT INTO statement.
Any help is appreciated!
The issue is almost certainly the fact that "Password", which you have used as a column name, is a reserved word. Any identifiers used in SQL code that are reserved words or contain special characters, e.g. spaces, must be escaped. A command builder doesn't do that by default. You have to set the QuotePrefix and QuoteSuffix properties yourself to make it do so. For an Access database, you would use "[" and "]" as the property values respectively.

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.

VB.NET - "There is no row at position 0" but Records in Database

Having a DataSet problem in VB.NET/Access.
Code should return 1 record and display the results on a form.
Basically when I step through the code in debug mode it returns 1 row and works fine,
but when I run the code without breakpoints I get the error message:
There is no row at position 0
VB.NET 2010 & MS Access 97
Dim sConnectionString As String = "dsn=MyDatabase"
Dim sSQL As String = ""
Dim DBConnection As New OdbcConnection(sConnectionString)
Dim dsMaster As New DataSet
Dim daMaster As New OdbcDataAdapter
Dim dtMaster As New DataTable
Try
DBConnection.Open()
sSQL = "SELECT * FROM myTable"
daMaster.SelectCommand = New OdbcCommand(sSQL, DBConnection)
daMaster.Fill(dsMaster, "MasterDataSet")
If dsMaster.Tables(0).Rows.Count <> 0 Then
dtMaster = dsMaster.Tables(0)
sItem1 = dtMaster.Rows(0).Item(0).ToString
sItem2 = dtMaster.Rows(0).Item(1).ToString
sItem3 = dtMaster.Rows(0).Item(2).ToString
Else
MessageBox.Show("No Records Available", "Error", MessageBoxButtons.OK)
End If
When I run the code, I get the messagebox saying No Records.
When I run in debug mode with a breakpoint on the IF statement, I get the messagebox saying No Records.
When I run in debug mode with a breakpoint on the FILL statement, I get 1 record returned and the code in IF statement executes.
Any ideas?
Here's how I would do it:
Dim sConnectionString As String = "dsn=MyDatabase"
Dim sSQL As String = ""
Dim DBConnection As New OdbcConnection(sConnectionString)
Dim dsMaster As New DataSet
Dim daMaster As New OdbcDataAdapter
Dim dtMaster As New DataTable
Try
DBConnection.Open()
sSQL = "SELECT * FROM myTable"
daMaster.SelectCommand = New OdbcCommand(sSQL, DBConnection)
daMaster.Fill(dsMaster)
If dsMaster.Tables(0).Rows.Count <> 0 Then
dtMaster = dsMaster.Tables(0)
sItem1 = dtMaster.Rows(0).Item(0).ToString
sItem2 = dtMaster.Rows(0).Item(1).ToString
sItem3 = dtMaster.Rows(0).Item(2).ToString
Else
MessageBox.Show("No Records Available", "Error", MessageBoxButtons.OK)
End If
I removed the "MasterDataSet" parameter value from daMaster.Fill() because adding it would leave dsMaster.Tables(0) empty and put all your query data in dsMaster.Tables("MasterDataSet").
Looks like this is most likely where your error was coming from.
Also you don't really need dtMaster because the data is already in a DataTable (dsMaster.Tables(0)) when you fill it.
So you would just reference those columns the same way:
sItem1 = dsMaster.Tables(0).Rows(0)(0).ToString
Keep in mind that providing the column names make it easier to read the code. So if you have the following query:
Dim sSQL As String = "SELECT Username, UserMail FROM Users WHERE UserID = 3"
Getting that data would look like this:
sItem1 = dsMaster.Tables(0).Rows(0)("Username")
You don't specifically need the .ToString added there, but if you don't get the data you expect, then add it in rather.