Visual Basic Project fails to update Microsoft Access database - vb.net

I have created a database that holds 3 values, the ID, UserName, and Score. I need to create a new entry to this database when the save button is clicked. My program needs to create a new row with the Username and score provided by the application.
This is my code to update an existing database:
Private Sub ButtonSaveScore_Click(sender As Object, e As EventArgs) Handles ButtonSaveScore.Click
provider = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source="
dataFile = "F:\Documents\Class Documents\CSC289 - K6A - Programming Capstone Project\Project\Scoreboard.accdb"
connString = provider & dataFile
myConnection.ConnectionString = connString
Using con As New OleDbConnection(connString),
cmd As New OleDbCommand("UPDATE [Scores] SET [UserName] = ?, [Score] = ? WHERE [ID] = ?", con)
con.Open()
cmd.Parameters.Add("#ID", OleDbType.Char).Value = "NEW"
cmd.Parameters.Add("#UserName", OleDbType.Char).Value = playerName
cmd.Parameters.Add("#Score", OleDbType.Char).Value = wins
cmd.ExecuteNonQuery()
End Using
End Sub
I get
oledb exception was unhandled
It highlights cmd.ExecuteNonQuery() and says data criteria mismatch.
Can someone give me advice to get this working?

You have a couple of issues there. Firstly, at least one of your parameters is the wrong data type. Secondly, your parameters are in the wrong order.
The Jet and ACE OLE DB providers only partially support named parameters, in that they allow you to use names so that your code can be clearer but they ignore the names and just use the positions. That means that you need to add the parameters to your OleDbCommand in the same order as they appear in the SQL code. You're not doing that so you have one issue there, although that's not the direct cause of your error message.
Even if those providers did fully support named parameters though, you're not using names in your SQL code. That means that there would be no way to match up parameters by name anyway, so how did you think that adding them in the wrong order wouldn't be an issue?
Given that all three of your parameters are specified as the same data type though, the incorrect order would not cause the error message you're seeing. If that data type was correct, you'd just find that the wrong data was saved to some of the columns, which would be even worse, i.e. appearing to work but not rather than just failing. You need to make sure that you use the correct OleDbType value for the column you're trying to save to. If your ID column in the database is specified to contain 32-bit numbers then you should be using OleDbType.Integer for the corresponding parameters. I'd also suggest using VarChar rather than Char unless your column is specifically fixed-width, which a Text column in Access is unlikely to be and I'm not sure even can be.

Related

How can i set the value from the last row in an specific column in a variable in VB.Net

I'm develop an application using forms in vb.net with visual studio 2019
I have code in the event click for one button
Dim oda As New OleDbDataAdapter
Dim ods As New DataSet
Dim consulta As String
Dim cadena As New OleDbConnection
Dim comando As New OleDbCommand
Try
cadena.Open()
comando = New OleDbCommand("Insert into QRQC (Nombre,NumControl,Fecha,Hora,Turno)" &
"values(txt_nombre,txt_numControl,lbl_fecha,lbl_hora,cBox_turno)", cadena)
consulta = "Select *From QRQC"
oda = New OleDbDataAdapter(consulta, cadena)
ods.Tables.Add("QRQC")
oda.Fill(ods.Tables("QRQC"))
Dim row As Integer
row = ods.Tables("QRQC").Rows.Count - 1
courrentId = ods.Tables("QRQC")(row)("ID_QRQC").ToString()
frm_newPt2.lbl_folioQRQC.Text = courrentId
cadena.Close()
Catch ex As Exception
MsgBox("Error al generar el registro en la base de datos", vbCritical, "Aviso")
Console.WriteLine(ex)
cadena.Close()
GoTo skip
End Try
Everything goes perfectly, but when I delete some record on my DB this part of the code always return the value 102
courrentId = ods.Tables("QRQC")(row)("ID_QRQC").ToString()
How can i solve this problem?
First of all, your insert command is wrong, and will not work.
You have "values(txt_nombre. etc etc."
But that is just a string and NOT the actual values from the form. So you are actually going to "instert txt_nombre" into that table and NOT the value of that label or text box on the form!!!
So you need to fix and get your insert command working FIRST.
And if this is just editing data then consider using the data binder, since navigation, editing, deleting and saving of data to/from the table can occur 100% automatic whiteout ANY code on your part.
so first up is to fix that insert command. You can't JUST use a string with the names of the controls else that would actually as noted try to insert the names of the controls as text and NOT the values of the controls.
And lets clean up a few other things. No need for a dataset, since a dataset is a SET of tables - we only dealing with one table (so use a data table).
But as noted, before we mess with data tables, we have to fix that insert command.
It will, can look like this:
Dim strSQL As String
strSQL = "Insert into QRQC (Nombre,NumControl,Fecha,Hora,Turno) " &
"VALUES(#nombre,#numControl,#fecha,#hora,#turno)"
Using cmdSQL As New OleDbCommand(strSQL,
New OleDbConnection(My.Settings.TestDB))
cmdSQL.Parameters.Add("#nombre", OleDbType.Integer).Value = txt_nombre.Text
cmdSQL.Parameters.Add("#numControl", OleDbType.Integer).Value = txt_numControl.Text
cmdSQL.Parameters.Add("#fecha", OleDbType.Integer).Value = lbl_fecha.Text
cmdSQL.Parameters.Add("#hora", OleDbType.Integer).Value = lbl_hora.Text
cmdSQL.Parameters.Add("#turno", OleDbType.Integer).Value = txt_nombre.Text
cmdSQL.Connection.Open()
cmdSQL.ExecuteNonQuery()
End Using
So you have to "replace" the string values in the sql with the ACTUAL values you are using.
You also don't show where/how you setup your connection to the database. I guessed that you used the applications settings and the connection builder - so you have to change TestDB to your actual connection that you used.
The above will thus get your insert command working.
At that point, you can post a new question in that after you do a insert, how to get the new autonumber primary key, or whatever else you wanted to do, but your insert statement as written will not work.
As noted, perhaps it better to use data bound controls. This will result in a Access like design experience, and you not having to write ANY code to edit a table in vb.net.
And it not clear if the control names I used are correct (or they are even controls on the form), but if they are, then ".Text" is required to grab the values. You have to of course change (check) that the control names I used and guessed are correct.
You also have to change the data type "integer" I used in above to the correct data types. For text I recommend you use .VarWChar

Read Value from Database in TextBox when Combobox text changes VB.NET

I have a list of Users Names in ComboBox and Some TextBoxes. When ComboBox text changes (i.e I select some username from ComboBox), The TextBoxes are filled with user details from the database.
I have code to achieve this in SQL Database. But these queries are not working with MsAccess database.
MysqlConn = New MySqlConnection
Mysql.ConnectionString = "server=localhost;user=root;password=root;database=database"
Dim READER As MySqlDataReader
Try
MysqlConn.open()
Dim Query As String
Query("select * from database.usernames where name='" & ComboBox1.Text & "'")
Command = New MySqlCommand(Query, MysqlConn)
READER = Command.ExecuteReader
While READER.Read
TextBox1.Text = READER.GetString("name")
End While
End Try
Here is my answer. Please don't get overwhelmed by it. ;)
Broken code
First of all, as I see it, the code you provided cannot work at all, because:
your Query variable is initialized in an invalid (or at least a very exotic) way. You probably want to use something like:
Dim Query As String
Query = "select * from database.usernames where name='" & ComboBox1.Text & "'"
or in a single line:
Dim Query As String = "select * from database.usernames where name='" & ComboBox1.Text & "'"
you try to assign the connection string to the ConnectionString property of a nonexistent Mysql variable. Or the variable exists because it is declared somewhere else, which might be a bug in your code snippet here. But I assume you want to assign the connection string to the MysqlConn.ConnectionString property instead.
you have not declared the MysqlConn and Command variables anywhere. You only just assign to them. (I will simply assume you have declared the variables correctly somewhere else in your code...)
the IDataRecord interface does not provide a GetString(name As String) method overload. So unless you have defined a custom extension method for it, you probably need to use the IDataRecord.GetOrdinal(name As String) method as well, or use the column index instead of the column name.
Anyway, the code you provided uses MySQL. So I assume that MySQL is the "SQL Database" you are using successfully. And that seems to work, as you say? Well... Hmmm... Then I will simply assume your code snippet is completely correct and works perfectly with MySQL... :/
MS Access vs. MySQL
Using MS Access requires other data access classes (probably the ones in namespace System.Data.OleDb) and another connection string. You could take a look at this ADO.NET OleDb example for MS Access in the Microsoft documentation.
You probably even have to update your SQL query, because every database system uses its own SQL dialect. You might want to consult the Office documentation for that. But your query is quite simple, so perhaps all you have to do to make it work with MS Access is:
remove the database name and use only the table name, and
delimit the name identifier (since it is a reserved keyword in MS Access).
I personally delimit all identifiers in my SQL queries, just to avoid unintended conflicts with reserved keywords. So I would personally use something like this:
select * from [usernames] where [name] = '...'
Additional tips
Also, I would like to provide you some additional (unrelated) tips regarding improving your code:
Use Using-statements with variables of an IDisposable type as much as possible. Those types/classes do not implement that interface if there isn't a good reason for it, so I consider it not unimportant to call Dispose when you are done with such disposable objects (or using a Using statement to call Dispose implicitly).
Use SQL parameters (if possible) to avoid SQL injection vulnerabilities. Look at this StackOverflow question and its answer for an example of how to use SQL parameters with MS Access.
Example
You may take a look at the following code snippet. It might not provide a working example out-of-the-box, but you might get some useful/practical ideas from it:
Dim connectionString As String = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=C:\\Data\\database.mdb;User Id=admin;Password="
Dim query As String = "select * from [usernames] where [name] = #Name"
Using conn As New OleDbConnection(connectionString)
Using command As New OleDbCommand(query)
command.Parameters.Add("#Name", OleDbType.VarChar, 50).Value = ComboBox1.Text
conn.Open()
Using reader As OleDbDataReader = command.ExecuteReader
If reader.Read Then
textbox1.Text = reader.GetString(reader.GetOrdinal("name"))
End If
End Using
End Using
End Using

How to use binary search in Visual Basic to search a Microsoft Access Database

I'm creating a program in Visual Basic for a school project. The program is a very simple tool to aid in the designing of a guitar. Users must login to use the program. I have setup an Access database to store all the data on the users and their designs. At the moment the login system uses SQL queries to find the inputted username in the database:
Private Sub cmd_login_Click(sender As Object, e As EventArgs) Handles cmd_login.Click
Call Login_Validation()
provider = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source ="
'access database location
dataFile = "C:\Users\Jackson\Desktop\Guitar Builder\Guitar Builder.accdb"
connString = provider & dataFile
myConnection.ConnectionString = connString
'the query:
myConnection.Open()
Dim cmd As OleDbCommand = New OleDbCommand("SELECT * FROM [Users] WHERE [Username] = '" & usn_box_login.Text & "' AND [Password] = '" & psw_box_login.Text & "'", myConnection)
Dim dr As OleDbDataReader = cmd.ExecuteReader
' userExists is set to true if the username user is found or false if it is not found
Dim userExists As Boolean = False
'if found:
While dr.Read
userExists = True
FullName = dr("Full Name").ToString
userName = dr("Username").ToString
End While
'checking the result
If userExists = True Then
Me.Hide()
Dashboard.Show()
Dashboard.lbl_name.Text = FullName
Dashboard.lbl_username.Text = userName
Else
MsgBox("Sorry, username or password not found", MsgBoxStyle.OkOnly, "Invalid Login")
End If
usn_box_login.Clear()
psw_box_login.Clear()
myConnection.Close()
End Sub
This works, however there must be a binary search in the program for it to pass the school's assessment. What is the easiest way to implement binary search to find the username?
Thank you in advance.
You can't. One of the advantages of using a DBMS like Access (or SQL Server, or SQLite, etc) is to abstract away the details of how data is retrieved and looked-up.
(Most modern database systems use special index structures for quick lookup, such as B-trees (B-trees are not Binary-search trees btw)
If the requirement is to use binary-search to find something, you need to not use something that will do it for you.
As this is for a programming exercise to demonstrate a working knowledge of data structures, I think you should remove Access completely and store data in a simple flat-file, load it all into memory when your program starts, then use your algorithms and structures to work with the data, before spitting it out to the flat-file store when your user clicks the Save button.
Note that I'm guessing using .NET's Array.BinarySearch is also probably cheating.
Other tips:
Don't store passwords in plain-text. They should not be encrypted either. Instead they should be hashed (and preferably salted).
Don't generate SQL using string concatenation. Use parameters instead. (Your code is vulnerable to SQL injection: if you put the text Baba O'Reilly in your textboxes your program will crash.
You should dispose of all your IDisposable objects correctly, ideally using a Using statement.
Run FxCop (Visual Studio Code Analysis) as part of your build process to catch other issues. Choose the "All Rules" setting.
The above bullet-points might sound like nit-picking, but I believe it's important to get into good habits early. The last thing an employer needs is a new hire who added significant vulnerabilities just because they never got used to doing things correctly.
I have taken your advice and removed Microsoft Access completely. I am now using my own record structure within the program.

VB Access DB Update statement

I am new to this forum, please could you help me get this code to work, when i execute it, it simply does nothing and does not update the DB. If i remove the square brackets it gives an error: "SYNTAX ERROR in UPDATE statement"
Any help appreciated!
Dim connection As OleDbConnection
connection = New OleDbConnection("Provider=Microsoft.ACE.OLEDB.12.0;Data Source=UserDB.accdb;Jet OLEDB:Database;")
connection.Open()
Dim pass As String
pass = txtconfirm.Text
Dim user As String
user = LoginForm.UsernameTextBox.Text
Dim query As String = "UPDATE [Users] SET [Password]= '" & pass & "' WHERE [Username]= '" & user & "';"
Dim command As New OleDbCommand(query, connection)
command.ExecuteNonQuery()
connection.Close()
Given your actual connection string, the database that will be updated is the one in the directory where your application starts. This means that if you work with a WinForms application this folder is \BIN\DEBUG or x86 variant. If there is not error then you could get the return value of the ExecuteNonQuery call to verify if a record has been updated or not
Dim rowsUpdated = command.ExecuteNonQuery()
MessageBox.Show("Record updated count = " & rowsUpdated)
If this value is not zero then your database has been updated and you are looking for changes in the wrong database. Check the one in the BIN\DEBUG folder.
In any case your code has big problems. If your variables user or pass contain a single quote, then your code will crash again because your string concatenation will form an invalid SQL. As usual the only workaround is to use a parameterized query
Dim pass = txtconfirm.Text
Dim user = LoginForm.UsernameTextBox.Text
Dim query As String = "UPDATE [Users] SET [Password]= #p1 WHERE [Username]= #p2"
Using connection = New OleDbConnection("...........")
Using command As New OleDbCommand(query, connection)
connection.Open()
command.Parameters.Add("#p1", OleDbType.VarWChar).Value = pass
command.Parameters.Add("#p2", OleDbType.VarWChar).Value = user
command.ExecuteNonQuery()
End Using
End Using
The parameterized approach has many advantages. Your query text is more readable, there is no misunderstanding between your code and the values expected by your database engine. And while not easy to exploit with MS-Access there is no problem with Sql Injection
I think Steve presents a much better approach for you coding this...
Let me just throw out a few more things:
The reason you can't take those brackets out is some of your column names are reserved words; just FYI.
Since you report "it does nothing..." when you execute, it sounds like you have a valid connection and sql syntax, in which case my next step would be to copy the sql command text while in debug mode, change it to a select and run it in your DB. You should get one result when you do. If not, either your criteria or field contents are not what you think they are...
Just change the Update table SET field-value ... to SELECT * FROM table and leave the WHERE clause as is.

SQL Column Does Not Exist Error

Okay, so basically I asked this little earlier today but we didn't get to the root of the problem and a lot of speculation was clouding the solutions. I have a program that currently needs to check a users inputed 'Gamer-Tag' from RegUserName.Text and compare that with Gamer-Tags stored on the SQL Table PersonsA which is in the Members_Details Database.
When the code is ran I receive the below error;
An unhandled exception of type 'System.ArgumentException' occurred in
System.Data.dll
Additional information: Column 'Gamer_Tag' does not belong to table
PersonsA.
However, Gamer-Tag IS in the Table; It's the second Column in the table. The Server is MS SQL Server and when I use the 'SQL Server Management Studio' I can clearly see the table & columns. From there all SQL Codes in relation to the Gamer_Tag column work flawlessly, so it's definitely in the database.
Here's the code which is called when a button is pressed. This code 'calls' the Function with the error.
Dim dbManager As New DatabaseManager() 'My Class Where The Functions Are
If dbManager.CheckGamerTagisMember(RegUserName.Text) Then
MsgBox("Gamer-Tag is NOT A Member.")
GoTo Ender
Else
MsgBox("Gamer-Tag is A Member.")
GoTo Ender
End If
And here's the Function which contains the Error;
Public Function CheckGamerTagisMember(ByVal gamertag As String) As Boolean
Connection = New SqlConnection("Data Source =" & My.Settings.ServerIP & ";Initial Catalog=Members_Details;Integrated Security=False;User=" & My.Settings.UserName & ";Password=*******;")
Connection.Open()
Dim gamertagDatSet As New DataSet()
usersDataAdapter.FillSchema(gamertagDatSet, SchemaType.Source, "PersonsA")
usersDataAdapter.Fill(gamertagDatSet, "PersonsA")
Dim table As DataTable = gamertagDatSet.Tables("PersonsA")
For i As Integer = 0 To table.Rows.Count - 1
Dim storedgamertag As String = table.Rows(i)("Gamer_Tag").ToString.ToString '<-------- ERROR
If (storedgamertag = gamertag) Then
gamertagDatSet.Dispose()
Connection.Close()
Return True
End If
Next
gamertagDatSet.Dispose()
Connection.Close()
Return False
End Function
What could cause this problem? I've checked obvious spelling and spacing, the firewall's off and the Column is without a doubt there. The function code was adapted from my SQL Login function, which worked without any issues, so I'm puzzled on why this isn't working.
Here's a screenshot from MS SQL Server Management Studio showing the PersonsA Table columns.
It's really getting frustrating now.
Some possible reasons:
Your user has actually been denied access to see the column. This can be accomplished via something as simple as:
DENY SELECT ON dbo.PersonsA(Gamer_Tag) TO your_user;
There is more than one PersonsA table, and the one you are accessing in your code is actually in a different schema than dbo. This is why you should always, always, always specify the schema when creating or referencing objects. Always. Read this post for more info.
Your code is connecting to a different server, a different database, or a different copy of the same database than Management Studio. (The latter can happen when using SQL Express and the User Instance/AttachDbFileName settings, which I can see that your code is not using, but I don't know if you are connecting to a user instance from Management Studio.)