How to Update my Access Database from textboxes - vb.net

i created a screen where i can edit the details in the database. but as soon as i click on the update button, it says no value given for one or more required parameters. i have attached my code....
Update BUtton...
Private Sub SimpleButton5_Click(sender As Object, e As EventArgs) Handles SimpleButton5.Click
Try
Access.AddParam("#UId", TextBox1.Text)
Access.AddParam("#ImagePic", PictureBox1.Image)
Access.AddParam("#Barcod", TextBox2.Text)
Access.AddParam("#BrandName", TextBox3.Text)
Access.AddParam("#StockName", TextBox4.Text)
Access.AddParam("#Category", TextBox5.Text)
Access.AddParam("#SubCat", TextBox6.Text)
Access.AddParam("#Subcat2", TextBox7.Text)
Access.AddParam("#Discrip", TextBox8.Text)
Access.AddParam("#StockLvl", TextBox9.Text)
Access.AddParam("#CustomAmount", TextBox10.Text)
Access.AddParam("#CostPrice", TextBox11.Text)
Access.AddParam("#Markup", TextBox12.Text)
Access.AddParam("#TaxAmount", TextBox13.Text)
Access.AddParam("#SellingPrice", TextBox14.Text)
Access.AddParam("#BeforTax", TextBox15.Text)
Access.AddParam("#AfterTax", TextBox16.Text)
Access.AddParam("#TaxPer", TextBox17.Text)
Access.AddParam("#MarkupPer", TextBox18.Text)
Access.AddParam("#LastDate", TextBox19.Text)
Access.AddParam("#LastUser", TextBox20.Text)
Access.ExecQuery("UPDATE Inventory " &
"SET [Image]=PictureBox1.image, BarCode=Textbox2.text, " &
"BrandName=#BrandName, StockName=#StockName, Category=#Category, SubCategory=#SubCat, " &
"SubCategory2=#SubCat2, Description=#Discrip, StockLevels=#StockLvl, CustomAmount=#Customamount, " &
"CostPrice=#CostPrice, MarkupAmount=#Markup, SellingPrice=#SellingPrice, ProfirBefore=#BeforeTax, " &
"ProfitAfter=#AfterTax, TaxAmount=#TaxAmount, taxPer=#TaxPer, MarkupPer=#MarkupPer, LastDateupdated=#LAstDate, " &
"UpserUpdated=#LastUser WHERE ID=#UId")
If NoErrors(True) = False Then Exit Sub
RefreshData()
Catch ex As Exception
MsgBox(ex.Message)
Finally
End Try
End Sub
My Access.ExecQuery --- (Class...)
Imports System.Data.OleDb
Public Class DBControl
Private DBCon As New OleDbConnection("Provider=Microsoft.ACE.OLEDB.12.0;Data Source=Database1.accdb;")
Private DBCmd As OleDbCommand
Public DBDA As OleDbDataAdapter
Public DBDT As DataTable
Public Params As New List(Of OleDbParameter)
Public RecordCount As Integer
Public Exception As String
Public Sub ExecQuery(Query As String)
RecordCount = 0
Exception = ""
Try
DBCon.Open()
DBCmd = New OleDbCommand(Query, DBCon)
Params.ForEach(Sub(p) DBCmd.Parameters.Add(p))
Params.Clear()
DBDT = New DataTable
DBDA = New OleDbDataAdapter(DBCmd)
RecordCount = DBDA.Fill(DBDT)
Catch ex As Exception
Exception = ex.Message
End Try
If DBCon.State = ConnectionState.Open Then DBCon.Close()
End Sub
' INCLUDE QUERY & COMMAND PARAMETERS
Public Sub AddParam(Name As String, Value As Object)
Dim NewParam As New OleDbParameter(Name, Value)
Params.Add(NewParam)
End Sub
End Class
I have played around with this for 2 days now, but somewhere i am missing something or overlooking something
thx
Jaco

The error message is pretty obvious. Some parameters are missing, either you forgot them or they are misspelled.
You need to double-check your code, it contains quite a few typos.
You are defining parameter #ImagePic, but it's not used in your query.
Same for #Barcod, you put this instead in your SQL: BarCode=Textbox2.text. Just call it #Barcode, why do you abbreviate names like that. That only creates confusion. Use proper English spelling and be consistent.
Another typo: Access.AddParam("#BeforTax", TextBox15.Text). In your SQL: ProfirBefore=#BeforeTax. ProfirBefore is a typo too.
Please do yourself a favor and rename the textboxes too: TextBox1 thru 20 is not good naming practice. There is good chance that you will mix up fields after doing copy-paste of your statements. Textbox20 is not intuitive at all and does not tell you what data you are handling.
I have played around with this for 2 days now, but somewhere i am missing something or overlooking something
Missing glasses perhaps :) I don't know about your development environment put I pasted your code in Notepad++ and by clicking on a keyword it highlights all occurrences of that keyword in the code. It quickly became obvious that some keywords were not being referenced anywhere.

I created a simple class for your Inventory object so I could avoid passing all of Properties as parameters. I can just pass the Inventory object to the UpdateDatabase method.
Public Class Inventory
Public Property Picture As Byte()
Public Property BarCode As String
Public Property BrandName As String
Public Property StockName As String
Public Property Category As String
Public Property SubCategory As String
Public Property SubCategory2 As String
Public Property Description As String
Public Property StockLevels As Integer
Public Property CustomAmount As Decimal
Public Property CostPrice As Decimal
Public Property MarkupAmount As Decimal
Public Property SellingPrice As Decimal
Public Property ProfitBefore As Decimal
Public Property ProfitAfter As Decimal
Public Property TaxAmount As Decimal
Public Property taxPer As Decimal
Public Property MarkupPer As Decimal
Public Property LastDateupdated As Date
Public Property UpserUpdated As String
Public Property ID As Integer
End Class
To get your picture box image in the proper format for storage I have a small function that takes an Image as a parameter and returns a Byte array.
'This Function requires Imports System.Drawing
Private Function GetByteArrayFromImage(img As Image) As Byte()
Dim convert As New ImageConverter
Dim arr = DirectCast(convert.ConvertTo(img, GetType(Byte())), Byte())
Return arr
End Function
Each property of the Inventory object is set. You can see that giving your controls meaningful names would help here. CInt, CDec, and CDate text boxes need to be validated before this code is reached.
I put the Try...Catch here so you could show a message to the user.
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim img As Image = PictureBox1.Image
Dim imgArray = GetByteArrayFromImage(img)
Dim inv As New Inventory With
{
.Picture = imgArray,
.BarCode = TextBox2.Text,
.BrandName = TextBox3.Text,
.StockName = TextBox4.Text,
.Category = TextBox5.Text,
.SubCategory = TextBox6.Text,
.SubCategory2 = TextBox7.Text,
.Description = TextBox8.Text,
.StockLevels = CInt(TextBox9.Text),
.CustomAmount = CDec(TextBox10.Text),
.CostPrice = CDec(TextBox11.Text),
.MarkupAmount = CDec(TextBox12.Text),
.SellingPrice = CDec(TextBox14.Text),
.ProfitBefore = CDec(TextBox15.Text),
.ProfitAfter = CDec(TextBox16.Text),
.TaxAmount = CDec(TextBox13.Text),
.taxPer = CDec(TextBox17.Text),
.MarkupPer = CDec(TextBox18.Text),
.LastDateupdated = CDate(TextBox19.Text),
.UpserUpdated = TextBox20.Text,
.ID = CInt(TextBox1.Text)
}
Try
UpdateDatabase(inv)
Catch ex As Exception
MessageBox.Show(ex.Message)
End Try
End Sub
In Access the order that the parameters appear in the sql statement must match the order that they are added to the parameters collection.
I thought it was odd that all your field names are capitalized except taxPer. Check your database.
Using...End Using blocks ensure that your database objects are closed and disposed even if there is an error.
The .Add method is superior to the method you were using because it includes datatypes and size. I had to guess at the types and sizes so check your database. Where I have guessed wrong, you will have to correct the .Add method, the type of the property in the Inventory class and the conversion of the text boxes .Text property. (3 places to change)
Private Sub UpdateDatabase(inv As Inventory)
Dim sql = "UPDATE Inventory SET
[Image]=#Picture,
BarCode= #BarCode,
BrandName=#BrandName,
StockName=#StockName,
Category=#Category,
SubCategory=#SubCat,
SubCategory2=#SubCat2,
Description=#Discrip,
StockLevels=#StockLvl,
CustomAmount=#Customamount,
CostPrice=#CostPrice,
MarkupAmount=#Markup,
SellingPrice=#SellingPrice,
ProfirBefore=#BeforeTax,
ProfitAfter=#AfterTax,
TaxAmount=#TaxAmount,
taxPer=#TaxPer,
MarkupPer=#MarkupPer,
LastDateupdated=#LAstDate,
UpserUpdated=#LastUser
WHERE ID=#UId"
Using cn As New OleDbConnection("Provider=Microsoft.ACE.OLEDB.12.0;Data Source=Database1.accdb;"),
cmd As New OleDbCommand(sql, cn)
With cmd.Parameters
.Add("#Picture", OleDbType.LongVarBinary).Value = inv.Picture
.Add("#BarCode", OleDbType.VarChar, 100).Value = inv.BarCode
.Add("#BrandName", OleDbType.VarChar, 100).Value = inv.BrandName
.Add("#StockName", OleDbType.VarChar, 100).Value = inv.StockName
.Add("#Category", OleDbType.VarChar, 100).Value = inv.Category
.Add("#SubCat", OleDbType.VarChar, 100).Value = inv.SubCategory
.Add("#SubCat2", OleDbType.VarChar, 100).Value = inv.SubCategory2
.Add("#Discrip", OleDbType.VarChar, 100).Value = inv.Description
.Add("#StockLvl", OleDbType.Integer).Value = inv.StockLevels
.Add("#Customamount", OleDbType.Decimal).Value = inv.CustomAmount
.Add("#CostPrice", OleDbType.Decimal).Value = inv.CostPrice
.Add("#Markup", OleDbType.Decimal).Value = inv.MarkupAmount
.Add("#SellingPrice", OleDbType.Decimal).Value = inv.SellingPrice
.Add("#BeforeTax", OleDbType.Decimal).Value = inv.ProfitBefore
.Add("#AfterTax", OleDbType.Decimal).Value = inv.ProfitAfter
.Add("#TaxAmount", OleDbType.Decimal).Value = inv.TaxAmount
.Add("#TaxPer", OleDbType.Decimal).Value = inv.taxPer
.Add("#MarkupPer", OleDbType.Decimal).Value = inv.MarkupPer
.Add("#LAstDate", OleDbType.Date).Value = inv.LastDateupdated
.Add("#LastUser ", OleDbType.VarChar, 100).Value = inv.UpserUpdated
.Add("#UId", OleDbType.Integer).Value = inv.ID
End With
cn.Open()
cmd.ExecuteNonQuery()
End Using
End Sub

Related

SQLite Error 20: Datatype mismatch in database insertion

Im making a POS style system and this is my code for storing the data for the active order and also inputting the data into the database. This should all work however I get an error on the cmd.ExecuteNonQuery() in the "Push" IF statement.
It gives me an SQLite error 20: Datatype mismatch.
And idea why?
TIA
Imports Microsoft.Data.Sqlite
Public Class CurrentOrder
Public Shared OrderID As Integer
Public Shared Items As New ArrayList
Public Shared ItemsString As String
Public Shared CustName As String
Public Shared Table As Integer
Public Shared Cost As Double 'How much the restaurant will have to pay to make the meal
Public Shared Price As Double 'How much the customer will pay for this order
Public Shared Sub Database(ByVal Mode As String)
Dim Connection As New SqliteConnection("Data Source = Database.db")
Dim SQLcommand As String
Dim CMD As New SqliteCommand
'ItemsString = ""
If Items.Count = 0 Then
MessageBox.Show("Please add items to order", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error)
Exit Sub
End If
If Mode = "Push" Then
For i = 0 To Items.Count - 1
ItemsString = ItemsString + Items(i) 'Concatatanation to take a list to a string
Next
Order.Label3.Text = ItemsString
SQLcommand = "INSERT INTO Orders VALUES ('#OrderID', '#ItemsString', '#CustName', '#Table', '#Cost', '#Price')" 'SQL Push Statement
Try
CMD.Connection = Connection
Connection.Open()
CMD.CommandText = SQLcommand
CMD.ExecuteNonQuery() 'Error 20: Datatype mismatch
Connection.Close()
Catch ex As Exception
MessageBox.Show(ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error)
End Try
ElseIf Mode = "Pull" Then
SQLcommand = ("SELECT * FROM Orders WHERE OrderID = " & OrderID) 'SQL Pull Statement
Try
CMD.Connection = Connection
Connection.Open()
CMD.CommandText = SQLcommand
Dim reader As SqliteDataReader = CMD.ExecuteReader()
While reader.Read()
Order.Label3.Text = reader("ItemID") & ", " & reader("Name") & ", " & reader("Price")
End While
reader.Close()
Connection.Close()
Catch e As Exception
MessageBox.Show(e.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error)
End Try
End If
End Sub
End Class
When dealing with money it is better to use Decimal rather than Double.
I don't know why this class has all these Shared items. It would probably be better to just create an instance in the calling code.
ArrayList should not be used in new code. See if List(Of T) will fill the bill.
Fields are not normally Public in Classes. You want a Property to be Public.
Classes like this have no user interface. You don't want to show message boxes from your class. Show the message boxes from you User Interface code in the Form Class.
Do not store several items in a single field in the database. You should have an Orders table with a primary key OrderID and an OrderDetails table for the items.
Your for loop just lumps all the items together. You will not be able to pull them apart again without any delimiter. Also, the concatenation operator in vb.net is &.
For you insert statement it is usually best to list the field names and then the values. I don't know why you're enclosed the parameter names in single quotes.
You can pass the CommandText and the Connection directly to the constructor of the Command.
You have referenced several parameters in your insert but you never added them to the parameters collection or set a value for them.
Apparently, you are providing a unique value for OrderID and this is not an auto number field.
Use a Sub New to put your order object in a stable state ready to have its data added to the database.
Public Class CurrentOrder
Public Property OrderID As Integer
Public Property Items As New List(Of String)
Public Property CustName As String
Public Property Table As Integer
Public Property Cost As Decimal 'How much the restaurant will have to pay to make the meal
Public Property Price As Decimal 'How much the customer will pay for this order
Public Sub New(ID As Integer, Itms As List(Of String), Name As String, TBL As Integer, Cst As Decimal, Prc As Decimal)
OrderID = ID
Items = Itms
CustName = Name
Table = TBL
Cost = Cst
Price = Prc
End Sub
End Class
The CurrentOrder class is completely separate from the DataAccess class.
Public Class DataAccess
Private ConStr As String = "Data Source = Database.db"
Public Sub SaveOrderAndDetails(O As CurrentOrder)
Dim OrderInsert = "INSERT INTO Orders (OrderID, CustName, Table, Cost, Price) VALUES (#OrderID, #CustName, #Table, #Cost, #Price)"
Using Connection As New SQLiteConnection(ConStr)
Using CMD As New SQLiteCommand(OrderInsert, Connection)
CMD.Parameters.Add("#OrderID", DbType.Int32).Value = O.OrderID
CMD.Parameters.Add("#CustName", DbType.String).Value = O.CustName
CMD.Parameters.Add("#Table", DbType.Int32).Value = O.Table
CMD.Parameters.Add("#Cost", DbType.Decimal).Value = O.Cost
CMD.Parameters.Add("#Price", DbType.Decimal).Value = O.Price
Connection.Open()
CMD.ExecuteNonQuery()
End Using
Dim DetailsInsert = "Insert Into OrderDetails (OrderID, Item) Values (#OrderId, #Item)"
Using cmd As New SQLiteCommand(DetailsInsert, Connection)
cmd.Parameters.Add("#OrderId", DbType.Int32).Value = O.OrderID
cmd.Parameters.Add("#Item", DbType.String)
For Each s In O.Items
cmd.Parameters("#Item").Value = s
cmd.ExecuteNonQuery()
Next
End Using
End Using
End Sub
Public Function GetOrderByID(id As Integer) As DataTable
Dim dt As New DataTable
Dim SqlCommand = "SELECT * FROM Orders WHERE OrderID = #ID"
Using cn As New SQLiteConnection(ConStr),
cmd As New SQLiteCommand(SqlCommand, cn)
cmd.Parameters.Add("#ID", DbType.Int32).Value = id
cn.Open()
Using reader = cmd.ExecuteReader
dt.Load(reader)
End Using
End Using
Return dt
End Function
Public Function GetOrderDetailByID(id As Integer) As DataTable
Dim dt As New DataTable
Dim sql = "Select Item From OrderDetails Where OrderID = #ID"
Using cn As New SQLiteConnection(ConStr),
cmd As New SQLiteCommand(sql, cn)
cmd.Parameters.Add("#ID", DbType.Int32).Value = id
cn.Open()
Using reader = cmd.ExecuteReader
dt.Load(reader)
End Using
End Using
Return dt
End Function
End Class
Finally, the usage of the classes in the user interface, in this case a windows form.
Private Sub Button1_Click() Handles Button1.Click
Dim lst As New List(Of String)
lst.Add("Bacon")
lst.Add("Eggs")
Dim newOrder As New CurrentOrder(7, lst, "John", 4, 12.03D, 22D)
Dim DA As New DataAccess
DA.SaveOrderAndDetails(newOrder)
End Sub
Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
Dim DA As New DataAccess
Dim dt = DA.GetOrderByID(7)
'Fill various text boxes with the DataTable fields
Dim dt2 = DA.GetOrderDetailByID(7)
DataGridView1.DataSource = dt2
End Sub
In the table, you have a different data type and you are sending a different datatype. For Example, In the table, you use Int and you pass decimal.

Database query not returning results from value

I am making a work management system and I am fairly new to Visual Basic.
What I am trying to do is retrieve the name of the employee from the database with the given ID. After that I want this name to be displayed in a Label. After that, he can press the Work Start or Work end buttons.
Here is the code:
Private Function employeeSearchwithID(PersonalNr As String) As String
Dim mitarbeiter As String
Dim r As DataRow
Access.ExecQuery("SELECT [Vorname], [Name] from [TA-Personal] WHERE ([Personal_Nr] = '" & PersonalNr & "');")
'Report and Abort on Erros or no Records found
If NoErros(True) = False Or Access.RecordCount < 1 Then Exit Function
r = Access.DBDT.Rows(0)
'Populate Label with Data
mitarbeiter = r.Item("Vorname") & " " & r.Item("Name")
Return mitarbeiter
End Function
It is used like this:
Private Sub tbxUserInput_KeyDown(sender As Object, e As KeyEventArgs) Handles tbxUserInput.KeyDown
If e.KeyCode = Keys.Enter Then 'employeeIDnumbersSelect()
Label5.Text = employeeSearchwithID(tbxUserInput.ToString)
End If
End Sub
So, the plan is to have this program running on a tablet connected to a scanner. Every employee will have a personal card. When they scan the card, I want their names to be displayed. Of course, the card will be with the ID. But I am having trouble with the names: when I give my personal number it comes up as an empty string.
I have a separate DB Module. I learned from a tutorial:
Imports System.Data.OleDb
Public Class DBControl
' DB Connection
Public DBCon As New OleDbConnection("Provider=Microsoft.Jet.OLEDB.4.0; Data Source=D:\recycle2000.mdb;")
'DB Command
Public DBCmd As OleDbCommand
'DB Data
Public DBDA As OleDbDataAdapter
Public DBDT As DataTable
'Public Myreader As OleDbDataReader = DBCmd.ExecuteReader
'Query Paramaters
Public Params As New List(Of OleDbParameter)
' Query Stats
Public RecordCount As Integer
Public Exception As String
Public Sub ExecQuery(Query As String)
'Reset Query Stats
RecordCount = 0
Exception = ""
Try
'Open a connection
DBCon.Open()
'Create DB Command
DBCmd = New OleDbCommand(Query, DBCon)
' Load params into DB Command
Params.ForEach(Sub(p) DBCmd.Parameters.Add(p))
' Clear params list
Params.Clear()
' Execute command & fill Datatable
DBDT = New DataTable
DBDA = New OleDbDataAdapter(DBCmd)
RecordCount = DBDA.Fill(DBDT)
Catch ex As Exception
Exception = ex.Message
End Try
' Close your connection
If DBCon.State = ConnectionState.Open Then DBCon.Close()
End Sub
' Include query & command params
Public Sub AddParam(Name As String, Value As Object)
Dim NewParam As New OleDbParameter(Name, Value)
Params.Add(NewParam)
End Sub
End Class
Without knowledge of the Access class, I have to recommend a different approach to querying the database. It is important to make sure that the database is not vulnerable to SQL injection, be it deliberate or accidental. The way to do that is to use what are known as SQL parameters: instead of putting the value in the query string, the value is supplied separately.
Private Function EmployeeSearchwithID(personalNr As String) As String
Dim mitarbeiter As String = String.Empty
Dim sql = "SELECT [Vorname], [Name] from [TA-Personal] WHERE [Personal_Nr] = ?;"
Using conn As New OleDbConnection("your connection string"),
cmd As New OleDbCommand(sql, conn)
cmd.Parameters.Add(New OleDbParameter With {.ParameterName = "#PersonalNr",
.OleDbType = OleDbType.VarChar,
.Size = 12,
.Value = personalNr})
conn.Open()
Dim rdr = cmd.ExecuteReader()
If rdr.Read() Then
mitarbeiter = rdr.GetString(0) & " " & rdr.GetString(1)
End If
End Using
Return mitarbeiter
End Function
Private Sub tbxUserInput_KeyDown(sender As Object, e As KeyEventArgs) Handles tbxUserInput.KeyDown
If e.KeyCode = Keys.Enter Then 'employeeIDnumbersSelect()
Dim employeeName = EmployeeSearchwithID(tbxUserInput.Text.Trim())
If String.IsNullOrEmpty(employeeName) Then
MessageBox.Show("Not found.", "Problem", MessageBoxButtons.OK, MessageBoxIcon.Exclamation)
Else
Label5.Text = employeeName
End If
End If
End Sub
The Using command makes sure that the "unmanaged resources" involved in querying a database are cleaned up afterwards, even if something goes wrong.
You will need to change the value of OleDbType.VarChar and .Size = 12 to match the type and size of that column in the database.
The name of the parameter is only for convenience with OleDb because it is ignored in the actual query, which uses "?" as a placeholder. Please see OleDbCommand.Parameters Property for full information.
If it still does not work, then please enter the ID manually in the tbxUserInput and see if you can make it work that way.
Hang on... tbxUserInput.ToString should be tbxUserInput.Text. But everything else I wrote still applies.

Database insert only works with integers, not strings

I'm attempting to insert into my database but this code only works when the variables are integers, any reason for this? Could using parameters fix this?
Public Class Floshcods
Private CardCodes As Integer
Private KeyWord As String
Private Definition As String
Public Sub New(ByVal CC As Integer)
CardCodes = CC
KeyWord = InputBox("Enter keyword")
Definition = InputBox("Enter definiton")
End Sub
Public Function GetCardCodes() As Integer
Return CardCodes
End Function
Public Function GetKeyWord() As String
Return KeyWord
End Function
Public Function GetDefinition() As String
Return Definition
End Function
End Class
================================================================
sub new()
Dim numb
Dim cn = ConnectDB()
Dim cmd As New MySqlCommand
Dim sql = "SELECT * FROM " & Tabelname & " ORDER by CardCode desc limit 1"
cmd.Connection = cn
cmd.CommandText = sql
cn.Open()
Dim result As MySqlDataReader = cmd.ExecuteReader
result.Read()
Try
numb = result.GetString(0)
Catch ex As Exception
MessageBox.Show("The selected table has no previous cards")
numb = 0
End Try
cn.Close()
Dim cardcode As Integer = numb + 1
Dim p As New Floshcods(cardcode)
Me.Controls("words" & 0).Text = p.GetKeyWord
Me.Controls("words" & 1).Text = p.GetDefinition
sql = "insert into " & Tabelname & " (CardCode,Keyword,Definition) VALUES (" & cardcode & ", " & p.GetKeyWord & ", " & p.GetDefinition & ");"
cmd.CommandText = sql
Try
cn.Open()
cmd.ExecuteNonQuery()
cn.Close()
Catch ex As Exception
MessageBox.Show("failed to add card")
End Try
end
If you need more of my code to understand, please ask.
The error I get is MySql.Data.MySqlClient.MySqlException: 'Unknown column 'test' in 'field list'.
Yes, the problem would be solved if you used SQL parameters for the values in the SQL query.
There are a few other changes that you might like to make to your code too:
It is usual to use properties rather than functions for values in a class.
Avoid Try..Catch where possible, e.g. if you can check for a value instead of having an error thrown, do so.
Some classes in .NET need to have .Dispose() called on their instances to tell it to clean up "unmanaged resources". That can be done automatically with the Using statement.
Option Strict On is useful to make sure that variable types are correct. You will also want Option Explict On. Option Infer On saves some keystrokes for when variable declarations have types obvious to the compiler.
So I suggest that you use:
Public Class Floshcods
Public Property CardCode As Integer
Public Property Keyword As String
Public Property Definition As String
Public Sub New(ByVal cardCode As Integer)
Me.CardCode = cardCode
Me.Keyword = InputBox("Enter keyword")
Me.Definition = InputBox("Enter definiton")
End Sub
End Class
and
Dim latestCardCode As Integer = 0
Dim sql = "SELECT CardCode FROM `" & Tabelname & "` ORDER BY CardCode DESC LIMIT 1;"
Using cn As New MySqlConnection("your connection string"),
cmd As New MySqlCommand(sql, cn)
cn.Open()
Dim rdr = cmd.ExecuteReader()
If rdr.HasRows Then
latestCardCode = rdr.GetInt32(0)
Else
MessageBox.Show("The selected table has no previous cards.")
End If
End Using
Dim cardcode = latestCardCode + 1
Dim p As New Floshcods(cardcode)
Me.Controls("words0").Text = p.Keyword
Me.Controls("words1").Text = p.Definition
sql = "INSERT INTO `" & Tabelname & "` (CardCode,Keyword,Definition) VALUES (#CardCode, #Keyword, #Definition);"
Using cn As New MySqlConnection("your connection string"),
cmd As New MySqlCommand(sql, cn)
cmd.Parameters.Add(New MySqlParameter With {.ParameterName = "#CardCode", .MySqlDbType = MySqlDbType.Int32, .Value = cardcode})
cmd.Parameters.Add(New MySqlParameter With {.ParameterName = "#Keyword", .MySqlDbType = MySqlDbType.VarChar, .Size = 64, .Value = p.Keyword})
cmd.Parameters.Add(New MySqlParameter With {.ParameterName = "#Definition", .MySqlDbType = MySqlDbType.VarChar, .Size = 99, .Value = p.Definition})
cn.Open()
Dim nRowsAdded As Integer = cmd.ExecuteNonQuery()
cn.Close()
If nRowsAdded = 0 Then
MessageBox.Show("Failed to add card.")
End If
End Using
You will need to change the .MySqlDbType and .Size to match how they are declared in the database.
I put backticks around the table name to escape it in case a reserved word is used or the name has spaces in it.
I changed the Functions to Properties in the Floshcods class and moved the InputBoxes to the User Interface code.
Public Class Floshcods
Public Property CardCodes As Integer
Public Property KeyWord As String
Public Property Definition As String
Public Sub New(ByVal CC As Integer)
CardCodes = CC
End Sub
End Class
I pulled out the data access code to separate methods so it will be easy to refactor to a data access layer. Also a method should be doing a single job and your Sub New was doing too much.
Using...End Using blocks ensure that your database objects are closed and disposed even if there is an error.
Always use parameters to avoid Sql injection. Datatypes are guesses. Check your database for the actual types.
Sub New()
Dim TableName = "SomeTableName"
Dim numb = GetMaxCarCode(TableName)
Dim cardcode As Integer = numb + 1
Dim p As New Floshcods(cardcode)
p.KeyWord = InputBox("Enter keyword")
p.Definition = InputBox("Enter definiton")
Controls("words0").Text = p.KeyWord
Controls("words1").Text = p.Definition
InsertFloshcods(TableName, p)
End Sub
Private Function GetMaxCarCode(Tablename As String) As Integer
Dim numb As Integer
Using cn As New MySqlConnection("Your connection string."),
cmd As New MySqlCommand($"Select MAX(CardCode) From {Tablename};", cn)
cn.Open()
numb = CInt(cmd.ExecuteScalar)
End Using
Return numb
End Function
Private Sub InsertFloshcods(TableName As String, f As Floshcods)
Using cn As New MySqlConnection("your connection String"),
cmd As New MySqlCommand($"Insert Into {TableName} (CardCode, Keyword, Definition) Values (#Code, #Keyword, #Def);", cn)
With cmd.Parameters
.Add("#Code", MySqlDbType.Int32).Value = f.CardCodes
.Add("#Keyword", MySqlDbType.VarChar).Value = f.KeyWord
.Add("#Def", MySqlDbType.VarChar).Value = f.Definition
End With
cn.Open()
cmd.ExecuteNonQuery()
End Using
End Sub

Unable to insert values into MS Access database

Can anyone please look at below code and advise what is wrong in this?
I was trying to insert values into an MS Access database. Compiler throws no error but the values are not inserted in table.
Code:
Private Sub btnSignInOK_Click(sender As Object, e As EventArgs) Handles btnSignInOK.Click
uniqid = "1"
Try
Dim ConnSignIn As New OleDb.OleDbConnection("Provider=Microsoft.ACE.OLEDB.12.0;Data Source=|DataDirectory|\Resources\DBpPNRGENERATORDATA.accdb;Persist Security Info=True")
Dim CmdSignIn As New OleDb.OleDbCommand
If Not ConnSignIn.State = ConnectionState.Open Then
ConnSignIn.Open()
End If
CmdSignIn.Connection = ConnSignIn
CmdSignIn.CommandText = "DELETE TEMPSIGNIN.* FROM TEMPSIGNIN WHERE IDENTIFIER='" + uniqid + "'"
CmdSignIn.ExecuteNonQuery()
CmdSignIn.CommandText = "INSERT INTO TEMPSIGNIN(IDENTIFIER,EPR,Partition,Host)VALUES('" & uniqid & "','" & tbSigninEPR.Text & "','" & cbSignInPartition.Text & "','" & tbSignInAl.Text & "')"
CmdSignIn.ExecuteNonQuery()
Catch ex As Exception
MessageBox.Show(ex.Message)
End Try
The DELETE command is not quite right. You do not need to specify the columns in a command as you are deleting the row not the columns:
DELETE FROM [TableName]
Next you should be using parameters when executing SQL commands. This is to reduce syntax issues but more importantly stops SQL injection. See Bobby Tables for more details on this. I use the ? placeholder within my SQL command when using parameters. I also specify the data type so consider using the OleDbParameter Constructor (String, OleDbType) to add your parameters.
I would also consider implementing Using:
Managed resources are disposed of by the .NET Framework garbage collector (GC) without any extra coding on your part. You do not need a Using block for managed resources. However, you can still use a Using block to force the disposal of a managed resource instead of waiting for the garbage collector.
You could implement a check for the value returned by ExecuteNonQuery() to see if the row was deleted before inserting the new row.
All together your code would look something like this:
uniqid = "1"
Dim rowDeleted As Boolean
Using con As New OleDbConnection("Provider=Microsoft.ACE.OLEDB.12.0;Data Source=|DataDirectory|\Resources\DBpPNRGENERATORDATA.accdb;Persist Security Info=True")
Using cmd As New OleDbCommand("DELETE FROM [TEMPSIGNIN] WHERE [IDENTIFIER] = ?", con)
con.Open()
cmd.Parameters.Add("#Id", OleDbType.Integer).Value = uniqid
rowDeleted = cmd.ExecuteNonQuery() = 1
End Using
If rowDeleted Then
Using cmd As New OleDbCommand("INSERT INTO [TEMPSIGNIN] ([IDENTIFIER], [EPR], [Partition], [Host]) VALUES (?, ?, ?, ?)", con)
cmd.Parameters.Add("#Id", OleDbType.[Type]).Value = uniqid
cmd.Parameters.Add("#EPR", OleDbType.[Type]).Value = tbSigninEPR.Text
cmd.Parameters.Add("#Partition", OleDbType.[Type]).Value = cbSignInPartition.Text
cmd.Parameters.Add("#Host", OleDbType.[Type]).Value = tbSignInAl.Text
cmd.ExecuteNonQuery()
End Using
End If
End Using
Note that I have used OleDbType.[Type]. You will want to replace [Type] with the data type you've used on your database.
As mentioned above, your syntax for the DELETE SQL is wrong. So when the database tries to execute it, it fails, so the INSERT never runs. Change the DELETE to:
CmdSignIn.CommandText = "DELETE FROM TEMPSIGNIN WHERE IDENTIFIER='" + uniqid + "'"
Also, you should learn how to use SQL Parameters and not use string concatenation to create a SQL string. Using parameters your DELETE query becomes something like (this is not 100%, it's off the top of my head)
CmdSignIn.CommandText = "DELETE FROM TEMPSIGNIN WHERE IDENTIFIER=#ID"
CmdSignIn.Parameters.Add("#ID", uniqid)
CmdSignIn.ExecuteNonQuery()
Okay, focusing on why there is no exception thrown no matter the syntax used. Are you sure you are targeting the right physical database?
If targeting the correct database, if the database is in Solution Explorer then select the database, select properties, check the property "Copy to Output Directory" the default is Copy Always, if you have this set then on each build the database in the project folder overwrite the database in the app folder directory thus no changes would be there.
Side note:
Going with the recommendations provided so far, here is a pattern to consider. Place all database operations in it's own class. The class below is simple, read, update, add and remove from a MS-Access database table Customers with (for this sample) a primary key, company name and contact name.
Each operation in it's own function with error handling which on failure you can get back the exception (I simply use the exception message for this sample).
A BindingSource is used as this component makes life easier when traversing data bound controls such as TextBoxes and or a DataGridView.
The form code displays data in a DataGridView, there is a button to remove the current record and a button to add a new record (I left out assertion to see if the TextBoxes have data). I used two TextBox controls to get information for inserting records.
Form code
Public Class StackOverFlowForm1
Private Operations As New Sample2
Private bsCustomers As New BindingSource
Private Sub StackOverFlowForm1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Dim ops As New Sample2
If ops.LoadCustomers Then
bsCustomers.DataSource = ops.CustomersDataTable
DataGridView1.DataSource = bsCustomers
Else
MessageBox.Show($"Failed to load table data{Environment.NewLine}{ops.Exception.Message}")
End If
End Sub
Private Sub cmdDeleteCurrent_Click(sender As Object, e As EventArgs) Handles cmdDeleteCurrent.Click
If bsCustomers.Current IsNot Nothing Then
Dim ops As New Sample2
Dim currentIdentifier As Integer = CType(bsCustomers.Current, DataRowView).Row.Field(Of Integer)("Identifier")
If Not ops.DeleteCustomer(currentIdentifier) Then
MessageBox.Show($"Failed to remove customer: {ops.Exception.Message}")
Else
bsCustomers.RemoveCurrent()
End If
End If
End Sub
Private Sub cmdInsert_Click(sender As Object, e As EventArgs) Handles cmdInsert.Click
Dim ops As New Sample2
Dim newId As Integer = 0
If ops.AddNewRow(txtCompanyName.Text, txtContact.Text, newId) Then
CType(bsCustomers.DataSource, DataTable).Rows.Add(New Object() {newId, txtCompanyName.Text, txtContact.Text})
Else
MessageBox.Show($"Failed to add customer: {ops.Exception.Message}")
End If
End Sub
End Class
Then we have a class for database operations. The database is located in the app folder.
Public Class Sample2
Private Builder As New OleDbConnectionStringBuilder With
{
.Provider = "Microsoft.ACE.OLEDB.12.0",
.DataSource = IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Database1.accdb")
}
Private mExceptiom As Exception
''' <summary>
''' Each method when executed, if there is an exception thrown
''' then mException is set and can be read back via Exception property
''' only when a method returns false.
''' </summary>
''' <returns></returns>
Public ReadOnly Property Exception As Exception
Get
Return mExceptiom
End Get
End Property
''' <summary>
''' Container for data read in from a database table
''' </summary>
''' <returns></returns>
Public Property CustomersDataTable As DataTable
Public Function LoadCustomers() As Boolean
If Not IO.File.Exists(Builder.DataSource) Then
Return False
End If
Try
CustomersDataTable = New DataTable
Using cn As New OleDbConnection With {.ConnectionString = Builder.ConnectionString}
Using cmd As New OleDbCommand With {.Connection = cn}
cmd.CommandText = "SELECT Identifier, CompanyName, ContactTitle FROM Customers"
cn.Open()
CustomersDataTable.Load(cmd.ExecuteReader)
CustomersDataTable.DefaultView.Sort = "CompanyName"
CustomersDataTable.Columns("Identifier").ColumnMapping = MappingType.Hidden
End Using
End Using
Return True
Catch ex As Exception
mExceptiom = ex
Return False
End Try
End Function
''' <summary>
''' Delete a customer by their primary key
''' </summary>
''' <param name="CustomerId"></param>
''' <returns></returns>
Public Function DeleteCustomer(ByVal CustomerId As Integer) As Boolean
Dim Success As Boolean = True
Dim Affected As Integer = 0
Try
Using cn As New OleDbConnection With {.ConnectionString = Builder.ConnectionString}
Using cmd As New OleDbCommand With {.Connection = cn}
cmd.CommandText = "DELETE FROM Customers WHERE Identifier = #Identifier"
cmd.Parameters.AddWithValue("#Identifier", CustomerId)
cn.Open()
Affected = cmd.ExecuteNonQuery()
If Affected = 1 Then
Success = True
End If
End Using
End Using
Catch ex As Exception
Success = False
mExceptiom = ex
End Try
Return Success
End Function
Public Function UpdateCustomer(ByVal CustomerId As Integer, ByVal CompanyName As String, ByVal ContactName As String) As Boolean
Dim Success As Boolean = True
Dim Affected As Integer = 0
Try
Using cn As New OleDbConnection With {.ConnectionString = Builder.ConnectionString}
Using cmd As New OleDbCommand With {.Connection = cn}
cmd.CommandText = "UPDATE Customer SET CompanyName = #CompanyName, ContactName = #ContactName WHERE Identifier = #Identifier"
cmd.Parameters.AddWithValue("#CompanyName", CompanyName)
cmd.Parameters.AddWithValue("#ContactName", ContactName)
cmd.Parameters.AddWithValue("#Identifier", ContactName)
cn.Open()
Affected = cmd.ExecuteNonQuery()
If Affected = 1 Then
Success = True
End If
End Using
End Using
Catch ex As Exception
Success = False
mExceptiom = ex
End Try
Return Success
End Function
''' <summary>
''' Add new row, if successful provide the new record's primary key
''' </summary>
''' <param name="Name"></param>
''' <param name="ContactName"></param>
''' <param name="Identfier"></param>
''' <returns></returns>
Public Function AddNewRow(ByVal Name As String, ByVal ContactName As String, ByRef Identfier As Integer) As Boolean
Dim Success As Boolean = True
Try
Using cn As New OleDbConnection With {.ConnectionString = Builder.ConnectionString}
Using cmd As New OleDbCommand With {.Connection = cn}
cmd.CommandText = "INSERT INTO Customers (CompanyName,ContactName) Values(#CompanyName,#ContactName)"
cmd.Parameters.AddWithValue("#CompanyName", Name)
cmd.Parameters.AddWithValue("#ContactName", ContactName)
cn.Open()
Dim Affected As Integer = cmd.ExecuteNonQuery()
If Affected = 1 Then
cmd.CommandText = "Select ##Identity"
Identfier = CInt(cmd.ExecuteScalar)
End If
End Using
End Using
Catch ex As Exception
Success = False
mExceptiom = ex
End Try
Return Success
End Function
End Class

SQL INSERT INTO not inserting into Access DB with no error message

I have the code inserting logins and data and then its supposed to update the database with INSERT INTO and I have it set up to give me a error message and I am not getting any, but none of them are coming up and when I check the Access file nothing has been added.
Private Sub AddLog()
Access.AddParams("#em1", em1)
Access.AddParams("#em2", em2)
Access.AddParams("#em3", em3)
Access.AddParams("#em4", em4)
Access.AddParams("#em5", em5)
Access.AddParams("#sit1", sit1)
Access.AddParams("#sit2", sit2)
Access.AddParams("#sit3", sit3)
Access.AddParams("#phys1", phys1)
Access.AddParams("#phys2", phys2)
Access.AddParams("#phys3", phys3)
Access.AddParams("#phys4", phys4)
Access.AddParams("#phys5", phys5)
Access.AddParams("#note", note)
Access.ExecQuery("INSERT INTO EmotionLoginDB (emotion1, emotion2, emotion3, emotion4, emotion5, situation1, situation2, situation3, physical1, physical2, physical3, physical4, physical5, notes) " & _
"VALUE (#em1, #em2, #em3, #em4, #em5, #sit1, #sit2, #sit3, #phys1, #phys2, #phys3, #phys4, #phys5, #note); ")
If Not String.IsNullOrEmpty(Access.exception) Then
End If
End Sub
And here is the database set up as well.
Imports System.Data.OleDb
Public Class DBControl
Private DBCon As New OleDbConnection("Provider=Microsoft.ACE.OLEDB.12.0;Data Source=StableMe.accdb;")
Private DBCmd As OleDbCommand
Public DBDA As OleDbDataAdapter
Public DBDT As DataTable
Public params As New List(Of OleDbParameter)
Public recordCt As Integer
Public exception As String
Public Sub ExecQuery(query As String)
recordCt = 0
exception = ""
Try
DBCon.Open()
DBCmd = New OleDbCommand(query, DBCon)
For Each p As OleDbParameter In params
DBCmd.Parameters.Add(p)
Next
params.Clear()
DBDT = New DataTable
DBDA = New OleDbDataAdapter(DBCmd)
recordCt = DBDA.Fill(DBDT)
Catch ex As Exception
exception = ex.Message
End Try
If DBCon.State = ConnectionState.Open Then
DBCon.Close()
End If
End Sub
Public Sub AddParams(name As String, value As Object)
Dim newParam As New OleDbParameter(name, value)
params.Add(newParam)
End Sub
End Class
I know its a lot and it's probably something simple, but I can't wrap my head around it.
the correct syntax is insert into TABLENAME(COLUMN1,COLUMN2,..) VALUES(..,..)