I am having trouble with my Data Save routine, saving data from several textbox's into an MSACCESS database. The code throws no errors, completes successful, but the database is not accessed. I assume it is the connection that is causing the problem but cannot see why. Can anyone suggest where I am going wrong? Thank you for looking.
cn = New OleDbConnection
cn.ConnectionString = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" & databaseName & "; Persist Security Info=False;"
Dim cmd As OleDbCommand = New OleDbCommand()
cmd.CommandType = CommandType.Text
cmd.CommandText = "UPDATE [BRLocoDatabase2] SET [aDate] = #aDate, [aDepot] = #aDepot, [bDate] = #bDate, [bDepot] = #bDepot," & _
" [cDate] = #cDate, [cDepot] = #cDepot, [dDate] = #dDate, [dDepot] = #dDepot WHERE [LOCO] = #Loco"
cmd.Parameters.AddWithValue("#Loco", TextBox1.Text)
cmd.Parameters.AddWithValue("#aDate", TextBox19.Text)
cmd.Parameters.AddWithValue("#aDepot", TextBox20.Text)
cmd.Parameters.AddWithValue("#bDate", TextBox21.Text)
cmd.Parameters.AddWithValue("#bDepot", TextBox22.Text)
cmd.Parameters.AddWithValue("#cDate", TextBox23.Text)
cmd.Parameters.AddWithValue("#cDepot", TextBox24.Text)
cmd.Parameters.AddWithValue("#dDate", TextBox25.Text)
cmd.Parameters.AddWithValue("#dDepot", TextBox26.Text)
cmd.Connection = cn
cn.Open()
cmd.ExecuteNonQuery()
MessageBox.Show("Update was a Success!")
cn.Close()
...
You are using OLEDB and OLEDB doesn't support named arguments. Your ability to use named parameters is just a syntactic sugar. Still those parameters are used by position. In your code, you have xDate which is likely dates, then xDepot and finally a where criteria Loco. But in your parameters you are adding Loco first and dDepot last. That would be interpreted like:
update .... set aDate = TextBox1.Text, ... where [Loco] = TextBox26.Text
Try changing your code to:
dim sql as String = <sql>UPDATE [BRLocoDatabase2]
SET [aDate] = #aDate, [aDepot] = #aDepot,
[bDate] = #bDate, [bDepot] = #bDepot,
[cDate] = #cDate, [cDepot] = #cDepot,
[dDate] = #dDate, [dDepot] = #dDepot
WHERE [LOCO] = #Loco</sql>
using cn as OleDbConnection = New OleDbConnection("Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" & databaseName & "; Persist Security Info=False;")
using cmd As OleDbCommand = New OleDbCommand(sql, cn)
cmd.Parameters.AddWithValue("#aDate", TextBox19.Text)
cmd.Parameters.AddWithValue("#aDepot", TextBox20.Text)
cmd.Parameters.AddWithValue("#bDate", TextBox21.Text)
cmd.Parameters.AddWithValue("#bDepot", TextBox22.Text)
cmd.Parameters.AddWithValue("#cDate", TextBox23.Text)
cmd.Parameters.AddWithValue("#cDepot", TextBox24.Text)
cmd.Parameters.AddWithValue("#dDate", TextBox25.Text)
cmd.Parameters.AddWithValue("#dDepot", TextBox26.Text)
cmd.Parameters.AddWithValue("#Loco", TextBox1.Text)
cn.Open()
cmd.ExecuteNonQuery()
MessageBox.Show("Update was a Success!")
cn.Close()
end using
end using
EDIT: BTW, instead of AddWithValue, try using Add, specify the corret types and convert those textBoxN.Text to corresponding types (ie: DateTime.TryParse for xDate values).
Ok, first, you probably really, but really want to put your connection string into some global settings to the project.
Not only will this save you having to re-type the connection ALL OVER the place in code, but you can also test the connection, and ensure it is valid.
So, project->"choose my project Properties.
Then settings:
So, now we get to use the connection builder.
(click on the [...])
Now:
then
Now, you can browse to the accDB (or mdb).
This:
And do NOT skip hitting advanced:
Then choose ACE (for accDB) or JET (for mdb)
this:
Now, if you are using vs2022, since it is now the FIRST version of VS to be x64 bits, then the test connection will NOT work (unless you using x64 Access/office).
But, at least now we have a connection string. If you using a pre-vs2022 version then test connection WILL work. As a additional step, you should set/force the project to x86.
Eg this:
DO NOT use "any cpu". You need/want/better force the project to x86 (x32 bits) if you using Access/ACE/Office x32.
On the other hand, if you using Access/ACE/Office x64, then of course you set/force the project to x64 bits.
Next up:
While you CAN USE named parameters with ACE and the oleDB provider?
The ORDER must be correct!! (only the position matters)
While I STILL suggest you use named parameters (since in the future, you can flip to SQL server or other oleDB providers, and THEY DO SUPPORT named providers.
So, keep in mind that you can use named parameters, but ONLY the order is what matters.
Another FYI:
Don't use addwith - use STRONG data typing.
So, this code should work:
Using conn As New OleDbConnection(My.Settings.TEST444)
Dim strSQL As String =
"UPDATE [BRLocoDatabase2] SET [aDate] = #aDate, [aDepot] = #aDepot, [bDate] = #bDate,
[bDepot] = #bDepot, [cDate] = #cDate, [cDepot] = #cDepot,
[dDate] = #dDate, [dDepot] = #dDepot WHERE [LOCO] = #Loco"
Using cmd As New OleDbCommand(strSQL, conn)
With cmd.Parameters
.Add("#aDate", OleDbType.Date).Value = TextBox19.Text
.Add("#aDepot", OleDbType.VarWChar).Value = TextBox20.Text
.Add("#bDate", OleDbType.Date).Value = TextBox21.Text
.Add("#bDepot", OleDbType.VarWChar).Value = TextBox22.Text
.Add("#cDate", OleDbType.Date).Value = TextBox23.Text
.Add("#dDepot", OleDbType.VarWChar).Value = TextBox26.Text
.Add("#dDate", OleDbType.Date).Value = TextBox25.Text
.Add("#cDepot", OleDbType.VarWChar).Value = TextBox24.Text
.Add("#Loco", OleDbType.Integer).Value = TextBox1.Text
End With
conn.Open()
cmd.ExecuteNonQuery()
MessageBox.Show("Update was a Success!")
End Using
End Using
Related
What I want to happen is if, textbox3.Text does not equal data(0) value then I want the MsgBox("test") to trigger. However, it does not. If the value of textbox3 does not exist with data(0) I want MsgBox("test") to trigger. I've tried every variation I could think of and I cannot get it to work.
Right now, if textbox.Text does not equal data(0) value nothing happens. However, if textbox3.Text equals data(0) then both Label3.Text = data(1) and MsgBox("Join code has been applied.") work.
Dim conn As New MySqlConnection
conn.ConnectionString = "server=;userid=;password=;database="
conn.Open()
Dim sqlquery As String = "SELECT * FROM joincodes WHERE code = '" & TextBox3.Text & "';"
Dim data As MySqlDataReader
Dim adapter As New MySqlDataAdapter
Dim command As New MySqlCommand
command.CommandText = sqlquery
command.Connection = conn
adapter.SelectCommand = command
data = command.ExecuteReader
While data.Read()
If data.HasRows() = True Then
If TextBox3.Text = data(0) Then
Label3.Text = data(1)
MsgBox("Join code has been applied.")
Else
MsgBox("test")
End If
End If
End While
There are a few things that need to be changed in the code.
Database connections have "unmanaged resources" associated with them, which means that you have to .Dispose() of them when you have finished using them. To avoid some fiddly code, VB.NET conveniently provides the Using statement.
It is best to give controls meaningful names because it is much easier to see what is going on in the code. E.g. if you accidentally typed TextBox37 when you meant TextBox87 it would be hard to see, but you wouldn't mistype tbUserName for tbFavouriteColour.
In MySQL, CODE is a keyword, so you need to escape it with backticks to be safe: MySQL Keywords and Reserved Words
Putting variables directly into SQL statements is generally a mistake. SQL parameters are used for doing that; they are easy to use and prevent a lot of problems.
If you are relying on the order of the columns from a database query (e.g. data(0)) then you must specify that order in the query (e.g. SELECT `col1`, `col2` FROM joincodes) because if you use * then they could be returned in any order.
You are probably only interested in the first returned value from the database (if there is a returned value), so I added the ORDER BY `col1` LIMIT 1.
Always use Option Strict On. It will save you time.
With regard to the question as asked, all you need to do is have a flag, I used a boolean variable named success, to indicate if things went right.
I also added some points indicated with 'TODO: in the following code which you'll need to take care of to make sure it works properly:
Option Infer On
Option Strict On
Imports MySql.Data.MySqlClient
' ... (other code) ... '
'TODO: Any type conversion from the string TextBox3.Text.'
'TODO: Give TextBox3 a meaningful name.'
Dim userCode = TextBox3.Text
Dim connStr = "your connection string"
Using conn As New MySqlConnection(connStr)
'TODO: Use the correct column names.'
Dim sql = "SELECT `col1`, `col2` FROM `joincodes` WHERE `code` = #code ORDER BY `col1` LIMIT 1"
Using sqlCmd As New MySqlCommand(sql, conn)
'TODO: Use correct MySqlDbType and change .Size if applicable.'
sqlCmd.Parameters.Add(New MySqlParameter With {.ParameterName = "#code", .MySqlDbType = MySqlDbType.String, .Size = 24, .Value = userCode})
Dim success = False
Dim rdr = sqlCmd.ExecuteReader()
If rdr.HasRows Then
rdr.Read()
'TODO: Change GetString to the appropriate Get<whatever>.'
If rdr.GetString(0) = userCode Then
success = True
'TODO: Check that `col2` is a string - change the GetString call as required and call .ToString() on the result if needed.'
Label3.Text = rdr.GetString(1)
MessageBox.Show("Join code has been applied.", "Success", MessageBoxButtons.OK, MessageBoxIcon.Information)
End If
End If
If Not success Then
MsgBox("test")
End If
End Using
End Using
I'm creating a .NET web application that retrieves data from a database. I keep getting the following error when running the below code though.
Fatal error encountered during command execution.
The InnerException is {"Parameter '?Username' must be defined."}, but I can see that ?Username is defined and I know that Session("Username") is correct and exists.
Here is the code. It fails on the SupervisorNameAdapter.Fill(SupervisorNameData, "Data") line.
Dim SupervisorID As String = Session("Username")
Dim qryGetSupervisorName As String = "select * from USERS where UserID = ?Username"
Using cn As New MySqlConnection(ConfigurationManager.ConnectionStrings("ConnectionInfo").ConnectionString), cmd As New MySqlCommand(qryGetSupervisorName, cn)
cmd.Parameters.AddWithValue("?Username", SupervisorID)
cn.Open()
cmd.ExecuteNonQuery()
cn.Close()
Dim SupervisorNameAdapter As New MySqlDataAdapter(qryGetSupervisorName, cn)
Dim SupervisorNameData As New DataSet
SupervisorNameAdapter.Fill(SupervisorNameData, "Data")
If SupervisorNameData.Tables(0).Rows.Count = 0 Then
MsgBox("An error has occured. Please refresh the page.", vbOKOnly, "Error!")
Else
SupervisorName.Text = SupervisorNameData.Tables(0).Rows(0).Item(1) & " " & SupervisorNameData.Tables(0).Rows(0).Item(2)
End If
End Using
Does anyone know why this is happening?
You are not setting correctly the command to be used by the MySqlAdapter. You just pass the command text string and with that string the adapter build another command that is missing the required parameter
Just change your code to
Dim SupervisorID As String = Session("Username")
Dim qryGetSupervisorName As String = "select * from USERS where UserID = ?Username"
Using cn As New MySqlConnection(ConfigurationManager.ConnectionStrings("ConnectionInfo").ConnectionString), cmd As New MySqlCommand(qryGetSupervisorName, cn)
cmd.Parameters.AddWithValue("?Username", SupervisorID)
Dim SupervisorNameAdapter As New MySqlDataAdapter(cmd)
Dim SupervisorNameData As New DataSet
....
End Using
I have a pc program used by dozens of people, and with the increase in people connecting to a database, the program began to throw the error with a large number of database connections. I checked the database after each query creates a process that is in the database as "sleep" if you exceeded the number 50 is the above error crashes. How can I remedy this if the problem lies with the program or hosting?
Database screen ;
http://obrazki.elektroda.pl/5375287900_1423553806.png
Code:
Public Sub loginUser(ByVal sql As String)
Try
Dim maxrow As Integer
con.Open()
dt = New DataTable
With cmd
.Connection = con
.CommandText = sql
End With
da.SelectCommand = cmd
da.Fill(dt)
maxrow = dt.Rows.Count
If maxrow > 0 Then
Form1.Show()
Else
Label3.Text = ("Invalid Username or Password!")
Label3.Visible = True
End If
Catch ex As Exception
MsgBox(ex.Message)
End Try
con.Close()
da.Dispose()
End Sub
Private Sub InsertData()
sql = "SELECT * from users WHERE login = '" & (username.Text) & "' and pass = '" & StringtoMD5(password.Text) & "'and banned = '" & 0 & "'"
loginUser(sql)
End Sub
When using database connections a special care should be used to correctly close and dispose these connections. If you don't do that correctly you end up with stale connections kept by your program and never reused by the pooling infrastructure of ADO.NET (See ADO.NET Connection Pooling)
The code in your example above has all the checks in place and should not be the cause of your problems but, are you sure that every where in your program you follow the same pattern without forgetting to dispose the involved objects?
The using statement is a life saver here because, EVEN in case of exceptions, you could be sure that the objects enclosed by the using statement are closed and disposed returning any unmanaged resources back to the system.
Another problem is your way to build SQL Commands concatenating strings. This leads directly to SQL Injection attacks and a very poor security standard for your application.
Said that, I think you should change your loginUser method to something like this
Public Sub loginUser(ByVal sql As String, ByVal parameterList as List(Of MySqlParameter))
Try
Dim maxrow As Integer
' local variables for connection, command and adapter... '
Using con = new MySqlConnection( ..connstring here.. )
Using cmd = con.CreateCommand()
con.Open()
With cmd
.Connection = con
.CommandText = sql
.Parameters.AddRange(parameterList.ToArray())
End With
Using da = new MySqlDataAdapter(cmd)
Dim dt = New DataTable
da.Fill(dt)
maxrow = dt.Rows.Count
If maxrow > 0 Then
Form1.Show()
Else
Label3.Text = ("Invalid Username or Password!")
Label3.Visible = True
End If
End Using
End Using
End Using
Catch ex As Exception
MsgBox(ex.Message)
End Try
End Sub
And call it with
Private Sub InsertData()
sql = "SELECT * from users " & _
"WHERE login = #uname " & _
"AND pass = #pwd " & _
"AND banned = '0'"
Dim parameterList = new List(Of MySqlParameter)()
parameterList.Add(new MySqlParameter("#uname", MySqlDbType.VarChar))
parameterList.Add(new MySqlParameter("#pwd", MySqlDbType.VarChar))
parameterList(0).Value = username.Text
parameterList(1).Value = StringtoMD5(password.Text)
loginUser(sql, parameterList)
End Sub
As I have said, just this change alone probably don't fix your problem. You should try to find in your program where you have a situation in which the connection is not properly closed and disposed. (and, at least, replace that code with the using statement)
I want to use classic ASP to open and close a connection to a SQL Server database and let it run a procedure from the database. It has no parameters.
This is the connection details in ASP, change caps to the relevant information objDBRS(0) will be your first part of data from a select statement
Set objDBConn = Server.CreateObject("ADODB.Connection")
objDBConn.Open "Provider=sqloledb;Data Source=SQLSERVERNAME;Initial Catalog=DATABASENAME; User ID=Chris;Password=PASSWORD;"
Set objDBCommand = Server.CreateObject("ADODB.Command")
objDBCommand.ActiveConnection = objDBConn
objDBCommand.CommandText = "SQLPROCEDURENAME"
objDBCommand.CommandType = adCmdStoredProc
Set objDBRS = Server.CreateObject("ADODB.RecordSet")
objDBRS.open objDBCommand,,adOpenForwardOnly
DO WHAT YOU WANT HERE
Set objDBCommand=nothing
objDBConn.Close
Set objDBConn=nothing
Here is a tried and tested approach I use over and over again.
<%
Dim cmd, conn_string, rs, data, row, rows
'Connection String if using latest version of SQL use SQL Server Native Client
'for more examples see http://www.connectionstrings.com/sql-server/
conn_string = "Provider=SQLNCLI11;Server=myServerAddress;Database=myDataBase;Uid=myUsername;Pwd=myPassword;"
Set cmd = Server.CreateObject("ADODB.Command")
With cmd
'No need to build ADODB.Connection the command object does it for you.
.ActiveConnection = conn_string
.CommandType = adCmdStoredProc
.CommandText = "[schema].[procedurename]"
Set rs = .Execute()
'Populate Array with rs and close and release ADODB.Recordset from memory.
If Not rs.EOF Then data = rs.GetRows()
Call rs.Close()
Set rs = Nothing
End With
'Release memory closes and releases ADODB.Connection as well.
Set cmd = Nothing
'Use Array to enumerate data without overhead of ADODB.Recordset.
If IsArray(data) Then
rows = UBound(data, 2)
For row = 0 To rows
'Read data
Call Response.Write("First Field: " & data(0, row))
Next
Else
'No records
Call Response.Write("No records to display")
End If
%>
Why won't this delete the data in my MySQL database!?
Private Sub Button4_Click(sender As System.Object, e As System.EventArgs) Handles Button4.Click
Dim dbCon As MySqlConnection
Dim strQuery As String = ""
Dim SQLCmd As MySqlCommand
Dim DR As MySqlDataReader
Try
dbCon = New MySqlConnection("Server=Localhost;Database=myusers;Uid=root;Pwd=Mypassword")
strQuery = "DELETE settings FROM settings WHERE user=" & Me.loginuser.Text
'* FROM settings WHERE user = "Testuser"'
SQLCmd = New MySqlCommand(strQuery, dbCon)
' OPEN THE DB AND KICKOFF THE QUERY
dbCon.Open()
DR = SQLCmd.ExecuteReader
While DR.Read
req1.Text = "" And exlink.Text = ""
End While
' DONE! Close DB
DR.Close()
dbCon.Close()
Catch ex As Exception
TextBox8.Text = ("Fail" & vbCrLf & vbCrLf & ex.Message)
End Try
Here is a picture of my database:
Alternatively I could somehow make it replace what is already in the database, in which case please help me with that.
Try
strQuery = "DELETE FROM settings " _
& " WHERE user = '" & Me.loginuser.Text & "'"
but as was stated earlier, you should be using parameterized queries. If you had a user named O'Brien then your query (as composed above) would fail because of the embedded single quote. When you use DELETE, you are deleting entire records and you already specify the table name in the FROM clause.
I will try to change your code in this way
Using con = New MySqlConnection("Server=.....")
con.Open()
Dim sqlText = "DELETE * FROM settings WHERE user = #ulogin"
Using cmd = new MySqlCommand(sqlText, con)
cmd.Parameters.AddWithValue("#ulogin", Me.loginuser.Text)
cmd.ExecuteNonQuery()
End Using
End Using
First and foremost, do not use string concatenation to create command texts to pass to the database engine. In that way you risk Sql Injections, also, if the user name contains a single quote (i.e. O'Hara) your code will fail with a syntax error (Same problems arise for date formatting, parsing numeric decimals and other globalization issues). Instead a parametrized query like the one in code above will avoid all of these problems.
In a parametrized query, the text of the query doesn't contains the actual value for the search condition or the update or insert data. Instead it contains placeholders ( in our case it is called #ulogin). The correct value to insert at the placeholders position is specified using one or more MySqlParameter added to the Parameters collection of the MySqlCommand. In this case I have used the AddWithValue method that derives the correct datatype directly from the datatype of the value. Because Me.loginuser.Text is a string value then the parameter will be treated as a string value replacing incorrect single quotes and removing extraneus characters usually used to Mount Sql Injections Attacks. The engine will do the rest inserting the correct value at the placeholder at execution time
EDIT: Seeing your comment about the MySql connector used, I will try to update my answer to show a semi-equivalent version for NET 1.
Try
Dim con As MySqlConnection = New MySqlConnection("Server=.....")
con.Open()
Dim sqlText as String = "DELETE * FROM settings WHERE user = #ulogin"
Dim cmd As MySqlCommand = new MySqlCommand(sqlText, con)
Dim par As MySqlParameter = New MySqlParameter("#ulogin", MySqlDbType.VarChar)
par.Value = Me.loginuser.Text
cmd.Parameters.Add(par)
cmd.ExecuteNonQuery()
Finally
con.Close()
End Try
I am not sure if the connector 1.0.10 supports the parameter name with the # prefix or just the : prefix
i dont think you can use double quotes in mysql, i think its single quotes only. try
Query = "DELETE * FROM settings WHERE user = '" & Me.loginuser.Text & "'"