Error while inserting image into access database - vb.net

I am trying to insert an image into my MS Access 2007 database. The datatype I chose is "OLEObject" and Fieldname as "Image".
I tried the following code which executes when a button is pressed:
Private Sub ButtonPress()
Dim cmd As New OleDbCommand
Dim MemStream As New IO.MemoryStream
Dim DataPic_Update As Byte()
Dim strImage As String
If Not IsNothing(PictureBox1.Image) Then
PictureBox1.Image.Save(MemStream, Imaging.ImageFormat.Png)
DataPic_Update = MemStream.GetBuffer
MemStream.Read(DataPic_Update, 0, MemStream.Length)
strImage = "?"
MemStream.Close()
Else
DataPic_Update = Nothing
strImage = "NULL"
End If
con.Open()
cmd.CommandText = "INSERT INTO Inventory([Image])" + "VALUES(#Image)"
cmd.Parameters.Add("#Image", OleDbType.Binary).Value = DataPic_Update
cmd.Connection = con
cmd.ExecuteNonQuery()
con.Close()
End Sub
While executing the command "ExecuteNonQuery", I am getting following Error:
"Data type mismatch in criteria expression."
I am not able to solve this error. Can someone please help me with any suggestions or modifications required in my existing code?
I want to insert the image and then retrieve from the access database.

There is no need to concatenate the cmd.CommandText, there is a space missing between "([Image])" and "VALUES(#Image)" so the resulting query is:
"INSERT INTO Inventory([Image])VALUES(#Image)"
Instead of
"INSERT INTO Inventory([Image]) VALUES(#Image)"
There is no need for the brackets surrounding "Image" as the field does not contain a space nor is a reserved keyword.
Check that you have all the dependencies needed to embed binary files in access. This dependencies are sometimes not very clear, per instance I remember that in Windows XP with Access XP you needed to install Paintbrush to be able to acomplish this.

I will recommend you to use the below code which I test on Access Database:
Private Function ReadFile(sPath As String) As Byte()
'Initialize byte array with a null value initially.
Dim data As Byte() = Nothing
'Use FileInfo object to get file size.
Dim fInfo As New FileInfo(sPath)
Dim numBytes As Long = fInfo.Length
'Open FileStream to read file
Dim fStream As New FileStream(sPath, FileMode.Open, FileAccess.Read)
'Use BinaryReader to read file stream into byte array.
Dim br As New BinaryReader(fStream)
'When you use BinaryReader, you need to supply number of bytes to read from file.
'In this case we want to read entire file. So supplying total number of bytes.
data = br.ReadBytes(CInt(numBytes))
fStream.Close()
fStream.Dispose()
Return data
End Function
And code to Save Image to MS Access Database
Dim logo() As Byte = ReadFile("E:\logo.jpg")
' Update(23373, logo)
Try
Dim CN As New OleDbConnection(Str_Conn)
CN.Open()
Dim cmd As New OleDbCommand("Update TblInventory Set Image=#img Where Image_ID=#id", CN)
cmd.Connection = CN
cmd.Parameters.Add(New OleDbParameter("#finger", DirectCast(logo, Object)))
cmd.Parameters.AddWithValue("#id", 51384)
cmd.ExecuteNonQuery()
CN.Close()
Catch ex As Exception
MessageBox.Show("Error Occured while Registering Finger Prints, Try Again" + ex.ToString(), "Error", MessageBoxButtons.OK, MessageBoxIcon.[Error])
End Try
Important Note: You must pass parameters in the Same Sequence you mentioned in Query.

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

Vb.NET MS Access SQL UPDATE Syntax Issue

I have been hammering away at this for hours but haven't gotten it right so I decided to post.
My Vb.NET app has a 2 Jpgs on the harddrive. One is LowRes and the other is HighRes. I want to save both pictures in the same record in a Microsoft Access 2007 database via INSERT, which works fine, and then UPDATE to add the second one. The UPDATE is not working.
I pieced together a bunch of code I found online for the INSERT code (learning as I go) and eventually figured something out that actually worked. However, trying to tweak the function to do a UPDATE to add the second picture is proving difficult. I suspect its something to do with me specifying parameters wrong?
The database has 1 table Records with 3 columns RecordID (which is Text, and a autonumber primary key which is pulled from Form1.Tb_RecordID.Text), HighRes (which is OLE) and LowRes (Which is also OLE). The database is named Database.accdb.
I call the subroutine with:
Save_To_Database("LowProfile.jpg", "LowRes")
if I want it to INSERT an OLE image in the "LowRes" column. I then call
Update_To_Database("HighProfile.jpg", "HighRes")
to update the record with the HighRes picture. I eventually want to consolidate these functions one to one and use ByVals to determine if it should Update or Insert.
This works fine:
Sub Save_To_Database(ByVal Filename As String, ByVal Res As String)
Dim cnString As String = "PROVIDER=Microsoft.ACE.OLEDB.12.0;Data Source=Database.accdb"
Dim theQuery As String = "INSERT INTO Records([RecordID],[" & Res & "]) values (" & Form1.Tb_RecordID.Text & ", #Img)"
Try
Dim fs As FileStream
fs = New FileStream(Filename, FileMode.Open, FileAccess.Read)
Dim picByte As Byte() = New Byte(fs.Length - 1) {}
fs.Read(picByte, 0, System.Convert.ToInt32(fs.Length))
fs.Close()
Dim CN As New OleDbConnection(cnString)
CN.Open()
Dim imgParam As New OleDbParameter()
imgParam.OleDbType = OleDbType.Binary
imgParam.ParameterName = "Img"
imgParam.Value = picByte
Dim cmd As New OleDbCommand(theQuery, CN)
cmd.Parameters.Add(imgParam)
cmd.ExecuteNonQuery()
MessageBox.Show("Image successfully saved.")
cmd.Dispose()
CN.Close()
CN.Dispose()
Catch ex As Exception
MessageBox.Show(ex.Message)
End Try
End Sub
However, my UPDATE code fails with a syntax error on the SQL statement:
Sub Update_To_Database(ByVal Filename As String, ByVal Res As String)
Dim cnString As String = "PROVIDER=Microsoft.ACE.OLEDB.12.0;Data Source=Database.accdb"
Dim theQuery As String = "UPDATE Records SET ([" & Res & "]) values (#Img) WHERE RecordID =" & Form1.Tb_RecordID.Text
MsgBox(theQuery)
Try
Dim fs As FileStream
fs = New FileStream(Filename, FileMode.Open, FileAccess.Read)
Dim picByte As Byte() = New Byte(fs.Length - 1) {}
fs.Read(picByte, 0, System.Convert.ToInt32(fs.Length))
fs.Close()
Dim CN As New OleDbConnection(cnString)
CN.Open()
Dim imgParam As New OleDbParameter()
imgParam.OleDbType = OleDbType.Binary
imgParam.ParameterName = "Img"
imgParam.Value = picByte
Dim cmd As New OleDbCommand(theQuery, CN)
cmd.Parameters.Add(imgParam)
cmd.ExecuteNonQuery()
MessageBox.Show("Image successfully saved.")
cmd.Dispose()
CN.Close()
CN.Dispose()
Catch ex As Exception
MessageBox.Show(ex.Message)
End Try
End Sub
Anyone see the problem? Or a way to improve the code?
Your original problem is the fact that you tried to write an update statement using the syntax of an insert statement. An easy fix would be simply to change the update statement to the correct syntax.
However, there are a number of things in your code that could be and should be changed, so I wrote an example based on your code that still can be improved further:
Sub Save_To_Database(ByVal Filename As String, ByVal RecordId As String, ByVal IsHighResolution As Boolean, ByVal IsNew As Boolean)
Dim theQuery As String
Dim cnString As String = "PROVIDER=Microsoft.ACE.OLEDB.12.0;Data Source=Database.accdb"
If IsNew Then
theQuery = "INSERT INTO Records([RecordID],[" & IIf(IsHighResolution, "HighRes", "LowRes") & "]) values (#RecordId, #Img)"
Else
theQuery = "UPDATE Records SET " & IIf(IsHighResolution, "HighRes", "LowRes") & " = #Img WHERE RecordID = #RecordId"
End If
Try
Using fs As New FileStream(Filename, FileMode.Open, FileAccess.Read)
Dim picByte As Byte() = New Byte(fs.Length - 1) {}
fs.Read(picByte, 0, System.Convert.ToInt32(fs.Length))
Using CN As New OleDbConnection(ConnectionString)
Dim cmd As New OleDbCommand(theQuery, CN)
cmd.Parameters.Add("Img", OleDbType.Binary).Value = picByte
cmd.Parameters.Add("#RecordId", OleDbType.Integer).Value = RecordId
CN.Open()
cmd.ExecuteNonQuery()
MessageBox.Show("Image successfully saved.")
End Using
End Using
Catch ex As Exception
MessageBox.Show(ex.Message)
End Try
End Sub
Points of interest:
Insert and update is now handled by the same method, only difference is a Boolean parameter that specifies if this is a new record or an existing one.
Queries are now safe from sql injection. The only concatenation here is the column name that you can't parameterize in sql, but it is decided inside the sub itself. When you use the sub, you only pass a boolean value indicating of this is a high resolution image.
The Using block is recommended to use whenever you are using anything that implements the IDisposable interface. This ensures the correct closer and disposal even in a case of an exception being thrown.
Parameters code simplified.

How to export data from Access to a text file

net. My question is how to export data from Access to a text file using vb.net. In my database has Table1 which consists FirstName and LastName so I want this data to be exported to a text file.
I stumble on this code and run it and when compiled it but nothing is export to the text file. Can Someone help my with this?
Dim connetionString As String
Dim cnn As OleDbConnection
connetionString = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=C:\Scripts\db.mdb;"
cnn = New OleDbConnection(connetionString)
cnn.Open()
Dim AccessCommand As New System.Data.OleDb.OleDbCommand("SELECT * INTO [Text;HDR=No;DATABASE=C:\Scripts\TextFiles].[Result.txt] FROM Table1", cnn)
cnn.Close()
Thanks in advance!
This question is downvoted is because you can actually find plenty of example from the website.
Perhaps you do not know what keyword to search?
Try something like "dataset to textbox"?
or something here? Export a C# DataSet to a text file
Updated
I understand you may be new to vb. I will not give you the exact code but tell you what you can do.
First, declare a dataTable/dataset (I would prefer DataTable) to hold your query result from DB.
Dim dtresult As DataTable = 'Result from DB
Then loop through the datatable rows and get the data append into a string builder(or any other way you like to build your string)
Then append the string into the txt file.
This is something you can do.
UPDATE 2
Okay, something like this.
Private Sub DataTableToTXT()
Dim connetionString As String
Dim cnn As OleDbConnection
connetionString = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=C:\Scripts\db.mdb;"
cnn = New OleDbConnection(connetionString)
Dim dtResult As New DataTable
cnn.Open()
'Change the query
Dim dataAdap As New OleDbDataAdapter("SELECT * FROM TABLE1", cnn)
dataAdap.Fill(dtResult)
cnn.Close()
'Change the path to your desired path
Dim exportPath As String = "C:\Export\"
Dim exportFileName As String = "data.txt"
If Not Directory.Exists(exportPath) Then
Directory.CreateDirectory(exportPath)
End If
Dim writer As New StreamWriter(exportPath + exportFileName)
Try
Dim sb As New StringBuilder
For Each row As DataRow In dtResult.Rows
sb = New StringBuilder
For Each col As DataColumn In dtResult.Columns
sb.Append(row(col.ColumnName))
Next
writer.WriteLine(sb.ToString())
Next
Catch ex As Exception
Throw ex
Finally
If Not writer Is Nothing Then writer.Close()
End Try
End Sub

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)