So I am working with blobs in visual basic, and I'm saving image files to a database. When I save them I have their name.jpg showing up in a combobox, but when I save another image and it refreshes the list, the name of the previous image shows twice. I'm not sure how I managed that. I am new to this so don't look down on me too much!
When the button on my form is clicked:
Private Sub btnSaveBlob_Click(sender As Object, e As EventArgs) Handles btnSaveBlob.Click
SaveBlobToDatabase()
refreshBlobList()
End Sub
My methods:
Private Sub SaveBlobToDatabase()
GetCompleteFilePath()
Dim BLOB() As Byte
Dim FileStream As New IO.FileStream _
(CompleteFilePath, IO.FileMode.Open, IO.FileAccess.Read)
Dim reader As New IO.BinaryReader(FileStream)
BLOB = reader.ReadBytes(CInt(My.Computer.FileSystem.GetFileInfo(CompleteFilePath).Length))
FileStream.Close()
reader.Close()
Dim SaveDocCommand As New SqlCommand
SaveDocCommand.Connection = conn
SaveDocCommand.CommandText = "INSERT INTO DocumentStorage" &
"(FileName, DocumentFile)" &
"VALUES (#FileName, #DocumentFile)"
Dim FileNameParameter As New SqlParameter("#FileName", SqlDbType.NChar)
Dim DocumentFileParameter As New SqlParameter("#DocumentFile", SqlDbType.Binary)
SaveDocCommand.Parameters.Add(FileNameParameter)
SaveDocCommand.Parameters.Add(DocumentFileParameter)
FileNameParameter.Value =
CompleteFilePath.Substring(CompleteFilePath.LastIndexOf("\") + 1)
DocumentFileParameter.Value = BLOB
Try
SaveDocCommand.Connection.Open()
SaveDocCommand.ExecuteNonQuery()
MessageBox.Show(FileNameParameter.Value.ToString &
"saved to database.", "BLOB Saved!", MessageBoxButtons.OK,
MessageBoxIcon.Information)
Catch ex As Exception
MessageBox.Show(ex.Message, "Save Failed",
MessageBoxButtons.OK, MessageBoxIcon.Error)
Finally
SaveDocCommand.Connection.Close()
End Try
End Sub
Private Sub refreshBlobList()
Dim GetBlobListCommand As New SqlCommand("SELECT FileName FROM DocumentStorage", conn)
Dim reader As SqlDataReader
GetBlobListCommand.Connection.Open()
reader = GetBlobListCommand.ExecuteReader
While reader.Read
lstBlob.Items.Add(reader(0))
End While
reader.Close()
GetBlobListCommand.Connection.Close()
If lstBlob.Items.Count > 0 Then
lstBlob.SelectedIndex = 0
End If
End Sub
Objects in .net that show you a .Dispose method should be disposed. They have unmanaged code and need to properly release things. Connections, Commands, Streams, and Readers fall into this group. Luckily .net has provided Using...End Using blocks that handle this for us even if there is an error. For this reason, these objects should be kept local to the methods where they are used.
As much as possible, methods should perform a single task. I pulled out the code to create the byte array to a separate Function. I also split the data access code from the user interace code. You may want to put the data access code in a separate class. This would come in handy if you want to change to a web app, for example.
In the data access code:
You can pass the connection string directly to the constructor of the connection. Likewise, pass the CommandText and Connection directly to the constructor of the command. The .Add method of the .Parameters collection will create a new parameter from the name and datatype passed to it. You can also set the value on the same line.
Private ConStr As String = "Your connection string"
Private Sub Button3_Click(sender As Object, e As EventArgs) Handles Button3.Click
Dim RowsAdded As Integer
Try
RowsAdded = SaveBlobToDatabase()
Catch ex As Exception
MessageBox.Show(ex.Message, "Save Failed", MessageBoxButtons.OK, MessageBoxIcon.Error)
End Try
If RowsAdded = 1 Then
MessageBox.Show("Saved to database.", "BLOB Saved!", MessageBoxButtons.OK, MessageBoxIcon.Information)
End If
End Sub
Private Function SaveBlobToDatabase() As Integer
Dim RowsAdded As Integer
Dim CompleteFilePath As String = GetCompleteFilePath()
Using conn As New SqlConnection(ConStr),
SaveCommand As New SqlCommand("INSERT INTO DocumentStorage(FileName, DocumentFile) VALUES(#FileName, #DocumentFile);", conn)
SaveCommand.Parameters.Add("#FileName", SqlDbType.NChar).Value = Path.GetFileName(CompleteFilePath) 'Requires Imports System.IO
SaveCommand.Parameters.Add("#DocumentFile", SqlDbType.Binary).Value = GetByteArrayFromFile(CompleteFilePath)
conn.Open()
RowsAdded = SaveCommand.ExecuteNonQuery()
End Using
Return RowsAdded
End Function
Private Function GetByteArrayFromFile(FullPath As String) As Byte()
Dim Blob() As Byte
Using FileStream As New IO.FileStream(FullPath, IO.FileMode.Open, IO.FileAccess.Read),
reader As New IO.BinaryReader(FileStream)
Blob = reader.ReadBytes(CInt(My.Computer.FileSystem.GetFileInfo(FullPath).Length))
End Using
Return Blob
End Function
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
lstBlob.Items.Clear()
lstBlob.DataSource = refreshBlobList()
lstBlob.DisplayMember = "FileName"
If lstBlob.Items.Count > 0 Then
lstBlob.SelectedIndex = 0
End If
End Sub
Private Function refreshBlobList() As DataTable
Dim dt As New DataTable
Using conn As New SqlConnection(ConStr),
GetBlobListCommand As New SqlCommand("SELECT FileName FROM DocumentStorage", conn)
conn.Open()
dt.Load(GetBlobListCommand.ExecuteReader)
End Using
Return dt
End Function
Related
I'm sorry for the log post but I am about to pull my hair out. I am attempting to import a PDF into a database.
The main error I am getting is: "Implicit conversion from data type varchar to varbinary(MAX) is not allowed. Use the CONVERT function to run this query."
Some of the coding included below is for a SEARCH function that is not yet completed. Please disregard that area of coding.
Basically I am loading a PDF in the AxAcroPDF1 box. This works great. It then pre-fills out a few of the textboxes. User inputs the Broker Load Number than hits save and a openfiledialog opens and the file is chosen to be imported. This then is where the failed import happens and the error above is given. I have tried many different avenues but always ending up with the same result. I am at a complete and total loss.
Table structure is as follows:
ID, int, NOT NULL IDENTITY(1,1) PRIMARY KEY,
BROKER_LOAD_NUMBER nvarchar(15) NOT NULL,
PDF_FILENAME,nvarchar(50) NOT NULL,
PETS_LOAD_NUMBER nvarchar(10) NOT NULL,
PAPERWORK varbinary(MAX) NOT NULL
My FULL code is as follows:
Imports System.Data.SqlClient
Public Class LoadDocs
Private DV As DataView
Private currentRow As String
Private Sub LoadDocs_Load(sender As Object, e As EventArgs) Handles MyBase.Load
'TODO: This line of code loads data into the 'DocDataset.Documents_Table' table. You can move, or remove it, as needed.
Documents_TableTableAdapter.Fill(DocDataset.Documents_Table)
End Sub
Private Sub btnOpenPDF_Click(sender As Object, e As EventArgs) Handles btnOpenPDF.Click
Dim CurYear As String = CType(Now.Year(), String)
On Error Resume Next
OpenFileDialog1.Filter = "PDF Files(*.pdf)|*.pdf"
OpenFileDialog1.ShowDialog()
AxAcroPDF1.src = OpenFileDialog1.FileName
tbFilePath.Text = OpenFileDialog1.FileName
Dim filename As String = tbFilePath.Text.ToString
tbFileName.Text = filename.Substring(Math.Max(0, filename.Length - 18))
Dim loadnumber As String = tbFileName.Text
tbPetsLoadNumber.Text = loadnumber.Substring(7, 7)
End Sub
Private Sub SearchResult()
Dim cmd As New SqlCommand
Dim reader As SqlDataReader
'SQL to get specific data from the Documents_Table
cmd.Parameters.Clear()
If cbColName.Text = "SEARCH BY:" Then
MeMsgBoxSearchCriteria.ShowDialog()
Else : lblSearchResults.Items.Clear()
Select Case DocDataset.Documents_Table.Columns(cbColName.Text).DataType
Case GetType(Integer)
DV.RowFilter = cbColName.Text & " = " & tbSearchInput.Text.Trim
Case GetType(Date)
DV.RowFilter = cbColName.Text & " = #" & tbSearchInput.Text.Trim & "#"
Case Else
DV.RowFilter = cbColName.Text & " LIKE '*" & tbSearchInput.Text.Trim & "*'"
End Select
If DV.Count > 0 Then
For IX As Integer = 0 To DV.Count - 1
lblSearchResults.Items.Add(DV.Item(IX)("PETS_LOAD_NUMBER"))
Next
If DV.Count = 1 Then
lblSearchResults.SelectedIndex = 0
Dim ix As Integer = DocumentsTableBindingSource.Find("PETS_LOAD_NUMBER", CInt(lblSearchResults.SelectedItem.ToString))
DocumentsTableBindingSource.Position = ix
Else
lblSearchResults.Visible = True
lblSearchResults.BringToFront()
End If
Else
' Display a message box notifying users the record cannot be found.
MeMsgBoxNoSearch.ShowDialog()
End If
End If
End Sub
Private Sub LbllSearchResults_SelectedIndexChanged(sender As Object, e As EventArgs) Handles lblSearchResults.SelectedIndexChanged
Dim ix As Integer = DocumentsTableBindingSource.Find("PETS_LOAD_NUMBER", CInt(lblSearchResults.SelectedItem.ToString))
DocumentsTableBindingSource.Position = ix
lblSearchResults.Visible = False
End Sub
Private Sub DocumentsTableBindingSource_PositionChanged(sender As Object, e As EventArgs) Handles DocumentsTableBindingSource.PositionChanged
Try
currentRow = DocDataset.Documents_Table.Item(DocumentsTableBindingSource.Position).ToString
Catch ex As Exception
MessageBox.Show(ex.Message)
End Try
End Sub
Private Sub BtnSavePDF_Click(sender As Object, e As EventArgs) Handles btnSavePDF.Click
If tbPetsLoadNumber.Text.Length = 0 Then
MessageBox.Show("Please enter a PETS Load Number", "Missing Load Number", MessageBoxButtons.OK, MessageBoxIcon.Exclamation)
Exit Sub
ElseIf tbBrokerLoadNumber.Text.Length = 0 Then
MessageBox.Show("Please enter a Broker Load Number", "Missing Load Number", MessageBoxButtons.OK, MessageBoxIcon.Exclamation)
Exit Sub
ElseIf tbFileName.Text.Length = 0 Then
MessageBox.Show("Please enter a Filename", "Missing Filename", MessageBoxButtons.OK, MessageBoxIcon.Exclamation)
Exit Sub
End If
Try
Using OpenFileDialog As OpenFileDialog = OpenFileDialog1()
If (OpenFileDialog.ShowDialog(Me) = DialogResult.OK) Then
tbFilePath.Text = OpenFileDialog.FileName
Else 'Cancel
Exit Sub
End If
End Using
'Call Upload Images Or File
Dim sFileToUpload As String = ""
sFileToUpload = LTrim(RTrim(tbFilePath.Text))
Dim Extension As String = Path.GetExtension(sFileToUpload)
upLoadImageOrFile(sFileToUpload, "PDF")
upLoadImageOrFile(sFileToUpload, Extension)
'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(tbFilePath.Text)
Dim numBytes As Long = fInfo.Length
'Open FileStream to read file
Dim fStream As New FileStream(tbFilePath.Text, FileMode.Open, FileAccess.Read)
'Use BinaryReader to read file stream into byte array.
Dim br As New BinaryReader(fStream)
'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))
'Insert the details into the database
Dim cmd As New SqlCommand
cmd.CommandText = "INSERT INTO Documents_Table (BROKER_LOAD_NUMBER, PDF_FILENAME, PETS_LOAD_NUMBER, PAPERWORK)
VALUES ('#bl', '#fn', '#pl', '#pdf');"
cmd.Parameters.AddWithValue("#fn", tbFileName.Text)
cmd.Parameters.AddWithValue("#p1", tbPetsLoadNumber.Text)
cmd.Parameters.AddWithValue("#bl", tbBrokerLoadNumber.Text)
cmd.Parameters.AddWithValue("#fp", tbFilePath.Text)
cmd.Parameters.AddWithValue("#pdf", data)
cmd.CommandType = CommandType.Text
cmd.Connection = New SqlConnection With {
.ConnectionString = My.MySettings.Default.PETS_DatabaseConnectionString
}
cmd.Connection.Open()
cmd.ExecuteNonQuery()
cmd.Connection.Close()
MsgBox("File successfully Imported to Database")
Catch ex As Exception
MessageBox.Show(ex.ToString())
End Try
End Sub
Private Sub upLoadImageOrFile(sFilePath As String, sFileType As String)
Dim cmd As New SqlCommand
Dim Data As Byte()
Dim sFileName As String
Dim qry As String
Try
'Read Image Bytes into a byte array
Data = ReadFile(sFilePath)
sFileName = Path.GetFileName(sFilePath)
'Set insert query
qry = "INSERT INTO Documents_Table (BROKER_LOAD_NUMBER, PDF_FILENAME, PETS_LOAD_NUMBER, PAPERWORK)
VALUES ('#bl', '#fn', '#pl', '#pdf')"
'Initialize SqlCommand object for insert.
cmd = New SqlCommand(qry, cmd.Connection)
'We are passing File Name and Image byte data as sql parameters.
cmd.Parameters.AddWithValue("#fn", tbFileName.Text)
cmd.Parameters.AddWithValue("#p1", tbPetsLoadNumber.Text)
cmd.Parameters.AddWithValue("#bl", tbBrokerLoadNumber.Text)
cmd.Parameters.AddWithValue("#fp", tbFilePath.Text)
cmd.Parameters.AddWithValue("#pdf", Data)
cmd.ExecuteNonQuery()
MessageBox.Show("File uploaded successfully")
Catch ex As Exception
MessageBox.Show("File could not uploaded")
End Try
End Sub
Private Function ReadFile(sFilePath As String) As Byte()
Throw New NotImplementedException()
End Function
End Class
I am trying to get multiple data sets from SQL Server using a VB.NET application. The problem that every time I try to execute the query,
I get this message:
Cannot change property 'ConnectionString'. The current state of the connection is open
Then I tried to fix it by enabling MARS
<connectionStrings>
<add name="ConString"
providerName="System.Data.SqlClient"
connectionString="Data Source=my-PC;Initial Catalog=Project;Persist Security Info=True; MultipleActiveResultSets=true;User ID=user;Password=*****" />
</connectionStrings>
This is my code
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim obj, body
obj = TextBox1.Text
body = TextBox2.Text
For Each mail In getemail()
Send_mail(mail, obj, body, getattachment(mail))
Next
MsgBox("Traitement effectué")
End Sub
Function getemail() As List(Of String)
Dim strMailTo As New List(Of String)
Dim SQL As String = "Select EMail FROM [USER] WHERE EMail Is Not NULL And MatriculeSalarie Is Not NULL And [EMail] <> '' and EtatPaie = 3 and BulletinDematerialise = 1 "
Dim cmd As New SqlCommand
Dim sqLdr As SqlDataReader
Dim dr As DataRow
Try
ConnServer()
cmd.Connection = con
cmd.CommandText = SQL
Using sda As New SqlDataAdapter(cmd)
Using ds As New DataTable()
sda.Fill(ds)
sqLdr = cmd.ExecuteReader()
For i = 0 To ds.Rows.Count - 1
dr = ds.Rows(i)
strMailTo.Add(dr("EMail"))
Next
End Using
End Using
Return strMailTo
sqLdr.Close()
Catch ex As Exception
MsgBox(ex.Message.ToString)
End Try
closeCon()
Return strMailTo
End Function
Function getattachment(email) As String()
Dim SQL As String = "Select MatriculeSalarie FROM [USER] WHERE [EMail]='" & email & "'"
Dim cmd As New SqlCommand
Dim sqLdr As SqlDataReader
ConnServer()
cmd.Connection = con
cmd.CommandText = SQL
Dim mat As String
mat = ""
Dim Dir As String = ConfigurationManager.AppSettings("path1").ToString
Dim file()
sqLdr = cmd.ExecuteReader()
While sqLdr.Read
mat = sqLdr.GetValue(sqLdr.GetOrdinal("MatriculeSalarie"))
End While
file = IO.Directory.GetFiles(Dir, mat.Substring(1) & "*.pdf")
sqLdr.Close()
Return file
End Function
If all you are going to do is show a message box in a Catch, don't do it in the database code. Let the error bubble up to the user interface code and put the Try around where the method is called.
Do not declare variables without a DataType. The button code with Option Infer on sets the type of obj and body.
Private ConStr As String = "Your connection string"
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim obj = TextBox1.Text
Dim body = TextBox2.Text
Dim emails As New List(Of String)
Try
emails = getemail()
Catch ex As Exception
MessageBox.Show(ex.Message.ToString, "Error retrieving email list")
Exit Sub
End Try
For Each email In emails
Try
Send_mail(email, obj, body, getattachment(email))
Catch ex As Exception
MessageBox.Show(ex.Message, "Error getting attachments")
End Try
Next
MessageBox.Show("Traitement effectué")
End Sub
Parameters used by Sub and Function must have a DataType.
I don't know what you are doing here.
While sqLdr.Read
mat = sqLdr.GetValue(sqLdr.GetOrdinal("MatriculeSalarie"))
End While
Each iteration will overwrite the previous value of mat. I can only assume that you expect only a single value, in which case you can use ExecuteScalar to get the first column of the first row of the result set. Don't do anything with the data until after the connection is closed. Just get the raw data and close (End Using) the connection. Manipulate the data later.
Always use Parameters. Parameters are not treated as executable code by the database server. They are simply values. An example of executable code that could be inserted is "Drop table [USER];" where the value of a parameter belongs. Oops!
Function getemail() As List(Of String)
Dim SQL As String = "Select EMail FROM [USER]
WHERE EMail Is Not NULL
And MatriculeSalarie Is Not NULL
And [EMail] <> ''
And EtatPaie = 3
And BulletinDematerialise = 1;"
Dim dt As New DataTable
Using con As New SqlConnection("Your connection string"),
cmd As New SqlCommand(SQL, con)
con.Open()
Using reader = cmd.ExecuteReader
dt.Load(reader)
End Using
End Using
Dim strMailTo As New List(Of String)
strMailTo = (From row As DataRow In dt.AsEnumerable
Select row.Field(Of String)(0)).ToList
Return strMailTo
End Function
Function getattachment(email As String) As String()
Dim SQL As String = "Select MatriculeSalarie FROM [USER] WHERE [EMail]='" & email & "'"
Dim mat As String
Using con As New SqlConnection(ConStr),
cmd As New SqlCommand(SQL, con)
cmd.Parameters.Add("#email", SqlDbType.VarChar).Value = email
con.Open()
mat = cmd.ExecuteScalar().ToString()
End Using
Dim Dir As String = ConfigurationManager.AppSettings("path1").ToString
'Your original code was fine, no need for searchPattern.
'I added this so you could see if your search pattern was what you expected.
Dim searchPattern = mat.Substring(1) & "*.pdf"
Debug.Print(searchPattern) 'Appears in the Immediate window
Dim file = IO.Directory.GetFiles(Dir, searchPattern)
Return file
End Function
I am simulating an ATM in Visual Basic. I have a table called Authentication in SQL. The Table contains two columns: The NUM_CARD column and the PIN_CARD column. I need to match row (0) column 1, row (1) column (1), row (2) column (1), and so on with the other rows as the card IDs are inserted. How can I do that? Thanks in advance.
The class DBConnection is the following:
Imports System
Imports System.Data.Sql
Imports System.Data.SqlClient
Public Class clsDBConnection
'Class variables'
Public cn As SqlConnection
Public cmd As SqlCommand
Public dr As SqlDataReader
'Constructor of the Connection class that creates the connection'
Sub New()
Try
cn = New SqlConnection("Data Source=JOVALLES-PC\SQLSERVEREX;Initial Catalog=SigmasBank;Integrated Security=True")
cn.Open()
Catch ex As Exception
MsgBox("Error connecting due to:: " + ex.ToString)
End Try
End Sub
'Returns true or false if the record exists or not in the database'
Function validationAutentication_p1(ByVal NUM_CARD As String) As Boolean
Dim result As Boolean = False
Try
cmd = New SqlCommand("Select * from Autentication where NUM_CARD='" & NUM_CARD & "'", cn)
dr = cmd.ExecuteReader
If dr.HasRows Then
result = True
End If
dr.Close()
Catch ex As Exception
MsgBox("Error in the procedure: " + ex.ToString)
End Try
Return result
End Function
Function validationAutentication_p2(ByVal PIN_CARD As String) As Boolean
Dim result As Boolean = False
Try
cmd = New SqlCommand("Select * from Autentication where PIN_CARD='" & PIN_CARD & "'", cn)
dr = cmd.ExecuteReader
If dr.HasRows Then
result = True
End If
dr.Close()
Catch ex As Exception
MsgBox("Error in the procedure: " + ex.ToString)
End Try
Return result
End Function
End Class
Insert Card ID Form:
Public Class FRM_InsertCardID
Public conn As New clsDBConnection
Private Sub BTN_Ok_Click(sender As Object, e As EventArgs) Handles BTN_Ok.Click
If TXB_CardID.Text.Length = 0 Then
MsgBox("Please fill in field.")
ElseIf TXB_CardID.Text.Length > 0 And TXB_CardID.Text.Length < 16 Then
MsgBox("Your Card ID must be 16 digits.")
ElseIf conn.validationAutentication_p1(TXB_CardID.Text) = False Then
MsgBox("The Card ID doesn't exist.")
Else
FRM_PIN.Show()
Me.Hide()
TXB_CardID.Text = ""
End If
End Sub
Insert PIN form:
Public Class FRM_PIN
Public conn As New clsDBConnection
Private Sub BTN_Ok_Click(sender As Object, e As EventArgs) Handles BTN_Ok.Click
If TXB_PIN.Text.Length = 0 Then
MsgBox("Please fill in field.")
ElseIf TXB_PIN.Text.Length > 0 And TXB_PIN.Text.Length < 4 Then
MsgBox("Your PIN must be 4 digits.")
ElseIf conn.validationAutentication_p2(TXB_PIN.Text) = False Then
MsgBox("Incorrect PIN Please try again.")
Else
FRM_Transaction.Show()
Me.Hide()
TXB_PIN.Text = ""
End If
End Sub
Not sure if typo causing issue otherwise?? - - Authentication
"I have a table called Authentication in SQL. "
" cmd = New SqlCommand("Select * from Autentication where PIN_CARD='" & PIN_CARD & "'", cn)"
Let's start with clsDBConnection. You do not need to import System. That is there by default. System.Data.Sql is never used. Get rid of that too.
One would think that this class is about a database connection. It is not. It contains code for authentication. So rename; something like DataAccess.
Never make connections, commands and readers class level variables. These database objects need to be closed and disposed so the class is not where to declare them. They need to be local variables, local to the method where they are used.
Never, never open a connection until directly before it is used. Ideally the line before an .Execute... method is called. Be sure it is also closed and disposed as soon as possible. Your code opens a connection and leaves it flapping in the breeze.
What you can do in a DataAccess class is make your connection string a Private class level variable. Private cnString as String = ...
I can't see where you would need a custom constructor at all. Just get rid of Sub New() I have made the 2 methods in your class Shared This data is shared by all instances of the class and you do not have declare an instance of the class to use these methods. You can call shared methods just by referencing the name of the class and the method. Also the conString is Shared because it is used by shared methods.
I decided that the pin number is not necessarily unique since they only go up to 9999. That is why I used 2 parameters for the second method.
Note:
I had to guess at the datatype and field size of the SqlParameters. Check your database and adjust the code accordingly.
Public Class FRM_InsertCardID
Private Sub BTN_Ok_Click(sender As Object, e As EventArgs) Handles BTN_Ok.Click
If TXB_CardID.Text.Length = 0 Then
MsgBox("Please fill in field.")
'Don't give the user any information on what a proper card ID consists of
Return
End If
If DataAccess.validationAutentication_p1(TXB_CardID.Text) = False Then
MsgBox("The Card ID doesn't exist.")
Else
FRM_PIN.Show()
'It appears you are using the default instance of FRM_PIN
FRM_PIM.CardID = TXB_CardID.Text
TXB_CardID.Text = ""
Me.Hide()
End If
End Sub
End Class
Public Class FRM_PIN
Friend CardID As String
Private Sub BTN_Ok_Click(sender As Object, e As EventArgs) Handles BTN_Ok.Click
If TXB_PIN.Text.Length = 0 Then
MsgBox("Please fill in field.")
Return 'Exits the sub
End If
If DataAccess.validationAutentication_p2(CardID, TXB_PIN.Text) = False Then
MsgBox("Incorrect PIN Please try again.")
Else
TXB_PIN.Text = ""
FRM_Transaction.Show()
Me.Hide()
End If
End Sub
End Class
Public Class DataAccess
Private Shared conString As String = "Data Source=JOVALLES-PC\SQLSERVEREX;Initial Catalog=SigmasBank;Integrated Security=True"
Public Shared Function validationAutentication_p1(ByVal NUM_CARD As String) As Boolean
Dim result = False
Using cn As New SqlConnection(conString),
cmd As New SqlCommand("Select * from Autentication where NUM_CARD= #NumCARD;", cn)
cmd.Parameters.Add("#NumCard", SqlDbType.VarChar, 16).Value = NUM_CARD
cn.Open()
Using dr = cmd.ExecuteReader
If dr.HasRows Then
result = True
End If
End Using
End Using
Return result
End Function
Public Shared Function validationAutentication_p2(ByVal CardID As String, ByVal PIN_CARD As String) As Boolean
Dim result = False
Using cn As New SqlConnection(conString),
cmd As New SqlCommand("Select * From Autentication where NUM_CARD = #NumCard AND PIN_CARD=#PinCard;", cn)
cmd.Parameters.Add("#NumCard", SqlDbType.VarChar, 100).Value = CardID
cmd.Parameters.Add("#PinCard", SqlDbType.VarChar, 4).Value = PIN_CARD
cn.Open()
Using dr = cmd.ExecuteReader()
If dr.HasRows Then
result = True
End If
End Using
End Using
Return result
End Function
End Class
I made two comboboxes. One of them depends on data from the other. When the first one selected index changes I need take the new value and use it to update the other. Here is what I have so far for the first combobox:
Try
Dim cmd As New SqlCommand("select * from tb_section ", connSql)
connSql.Open()
Dim dr As New SqlDataAdapter(cmd)
Dim table As New DataTable
dr.Fill(table)
compsec.DataSource = table
compsec.DisplayMember = "sec_name"
compsec.ValueMember = "sec_code"
Catch ex As Exception
MsgBox(ex.Message)
connSql.Close()
Finally
connSql.Close()
End Try
And here is code for the other combo box:
Public Sub all_group_list(sectioncode)
Try
Dim cmd As New SqlCommand("select * from tb_group where sec_code= " & sectioncode.ToString, connSql)
connSql.Open()
Dim dro As New SqlDataAdapter(cmd)
Dim table As New DataTable
dro.Fill(table)
compgroup.DataSource = table
compgroup.DisplayMember = "group_name"
compgroup.ValueMember = "group_code"
Catch ex As Exception
MsgBox(ex.Message)
connSql.Close()
Finally
connSql.Close()
End Try
End Sub
When the first combobox index changes I run this code:
Private Sub compsec_SelectedIndexChanged(sender As Object, e As EventArgs) Handles compsec.SelectedIndexChanged
connSql.Close()
all_group_list(compsec.SelectedValue.ToString)
End Sub
It's not clear what problem you're actually having, but there are several fixes in the code below. Name: don't use string concatenation to put data into an SQL command! Also, don't try to re-use the same connection object throughout an application. Only share the connection string, as sharing the same connection object interferes with the connection pooling feature in ADO.Net. Further, the DataAdapter will handle opening and closing the connection for you, and a Using block, rather than a Finally block, is the best way to be sure the connection closes if an exception is thrown.
Try
Dim ds As New DataSet
Using cn As new SqlConnection(connSql.ConnectionString), _
cmd As New SqlCommand("select sec_name, sec_code from tb_section", cn), _
da As New SqlDataAdapter(cmd)
da.Fill(ds)
End Using
compsec.DisplayMember = "sec_name"
compsec.ValueMember = "sec_code"
compsec.DataSource = ds.Tables(0)
Catch ex As Exception
MsgBox(ex.Message)
End Try
.
Public Sub all_group_list(sectioncode)
Try
Dim ds As New DataSet
Using cn As New SqlConnection(connSql.ConnectionString), _
cmd As New SqlCommand("select group_name, group_code from tb_group where sec_code= #SectionCode", cn), _
da As New SqlDataAdapter(cmd)
'Had to guess at column type/length here. Use the actual column definition from your database
cmd.Parameters.Add("#SectionCode", SqlDbType.NVarChar, 10).Value = sectioncode
da.Fill(ds)
End Using
compgroup.DisplayMember = "group_name"
compgroup.ValueMember = "group_code"
compgroup.DataSource = ds.Tables(0)
Catch ex As Exception
MsgBox(ex.Message)
End Try
End Sub
.
Private Sub compsec_SelectedIndexChanged(sender As Object, e As EventArgs) Handles compsec.SelectedIndexChanged
all_group_list(compsec.SelectedValue.ToString())
End Sub
I am having difficulty updating an existing row in an Access Database using VB. I want to be able to make changes to fields in an already populated existing row in my access table.
The code I have relates to adding a new record at the bottom of the table rather than the above.
Public Class Form1
Dim objConnection As New OleDb.OleDbConnection("Provider=Microsoft.ACE.OLEDB.12.0; Data Source = StudentDatabase.accdb")
Dim objStudentDA As New OleDb.OleDbDataAdapter("Select * FROM Student", objConnection)
Dim objStudentCB As New OleDb.OleDbCommandBuilder(objStudentDA)
Dim objDs As New DataSet()
Private Sub btnUpdate_Click(sender As Object, e As EventArgs) Handles btnUpdate.Click
If txtStudentNum.Text <> "" And txtSurname.Text <> "" And txtAttendance.Text <> "" And txtCA1.Text <> "" And txtCA2.Text <> "" And txtFinalExamResult.Text <> "" Then
Dim objRow3 = objDs.Tables("Student").Rows.Find(txtUpdateStudentID.Text.ToString)
'Editing each field value based on textboxes
objRow3.Item("FName") = txtUpdateFName.Text
objRow3.Item("SName") = txtUpdateSName.Text
objRow3.Item("Attendance") = txtUpdateAttendance.Text
objRow3.Item("CA1") = txtUpdateCA1.Text
objRow3.Item("CA2") = txtUpdateCA2.Text
objRow3.Item("FinalExam") = txtUpdateFinalExam.Text
objRow3.Item("OverallResult") = txtUpdateOverallGrade.Text
**'ERROR HERE STATING THIS ROW ALREADY BELONGS TO A TABLE**
objDs.Tables("Student").Rows.Add(objRow3)
objStudentDA.Update(objDs, "Student")
MsgBox("Record has been added to the IS2215 Database!")
Retrieve()
Else
MsgBox("Error: You must not leave any fields blank!")
End If
End Sub
Public Sub Retrieve()
objDs.Clear()
objStudentDA.FillSchema(objDs, SchemaType.Source, "Student")
objStudentDA.Fill(objDs, "Student")
cmbStudentFind.Items.Clear()
Dim i As Integer, strCurrentID As String
For i = 1 To objDs.Tables("Student").Rows.Count
strCurrentID = objDs.Tables("Student").Rows(i - 1).Item("ID")
cmbStudentFind.Items.Add(strCurrentID)
cmbUpdateStudentID.Items.Add(strCurrentID)
Next
cmbStudentFind.SelectedIndex = 0
cmbUpdateStudentID.SelectedIndex = 0
FillUpdateDetails()
End Sub
Public Sub FillUpdateDetails()
Dim objRow2 As DataRow
objRow2 = objDs.Tables("Student").Rows.Find(cmbUpdateStudentID.SelectedItem.ToString)
txtUpdateStudentID.Text = objRow2.Item("ID")
txtUpdateFName.Text = objRow2.Item("FName")
txtUpdateSName.Text = objRow2.Item("SName")
txtUpdateAttendance.Text = objRow2.Item("Attendance")
txtUpdateCA1.Text = objRow2.Item("CA1")
txtUpdateCA2.Text = objRow2.Item("CA2")
txtUpdateFinalExam.Text = objRow2.Item("FinalExam")
txtUpdateOverallGrade.Text = objRow2.Item("OverallResult")
End Sub
End Class
You need to execute CRUD against your Database. You will have a lot of problems trying to perform those operations against Access, as it tends to lock Tables when a Table is being accessed.
I would suggest you build a CRUD framework to "machine gun" the Insert, Update, and/or Delete operations into Access as you need.
Outside of that, you will loose a lot of hair in the process of trying to make it work.
For making inserts, you can stick with your current TextBox setup. For making updates, I would think a DataGridView would be a better way to go.
Something like this should work for you.
Imports System.Data.OleDb
Public Class Form1
Dim connetionString As String
Dim connection As OleDbConnection
Dim oledbAdapter As OleDbDataAdapter
Dim oledbCmdBuilder As OleDbCommandBuilder
Dim ds As New DataSet
Dim changes As DataSet
Dim i As Integer
Dim sql As String
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
connetionString = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=Your mdb filename;"
connection = New OleDbConnection(connetionString)
Sql = "select * from tblUsers"
Try
connection.Open()
oledbAdapter = New OleDbDataAdapter(Sql, connection)
oledbAdapter.Fill(ds)
DataGridView1.Data Source= ds.Tables(0)
Catch ex As Exception
MsgBox(ex.ToString)
End Try
End Sub
Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click
Try
oledbCmdBuilder = New OleDbCommandBuilder(oledbAdapter)
changes = ds.GetChanges()
If changes IsNot Nothing Then
oledbAdapter.Update(ds.Tables(0))
End If
ds.AcceptChanges()
MsgBox("Save changes")
Catch ex As Exception
MsgBox(ex.ToString)
End Try
End Sub
End Class
Or, you can stick with the TextBox concept, and change your setup slightly, as such.
str = "Journals SET JournalTitle=?, JournalText=? WHERE JournalDate=?"
cmd = New OleDbCommand(str, myConnection)
cmd.Parameters.AddWithValue("#jounalTitle", MyJournalTitle )
cmd.Parameters.AddWithValue("#journalText", MyJournalText)
cmd.Parameters.AddWithValue("#journalDate", DatePicked)
cmd.ExecuteNonQuery()
That methodology is much safer than the way you are doing it now. There are more details here.
How to update MS Access Database (vb.net)