"Connection was not closed. Connection's current State was open"- Ms Access Visual Basic- Visual Studio 2010 - vb.net

My connection between my project and my Ms Access 2010 Database seems to be right at the moment of logging in with my project. However, After the first trial(if user and/or password are incorrect), when I try to log in again, the error is given. It says "Connection was not closed. Connection's current State was open". I just have found possible solutions for MySql service, but I'm using Ms Access database. The code where the error seems to be given is the following. Any suggestions?, please:
Public Function Validation()
da.Fill(dt)
connection.Open()
For Each DataRow In dt.Rows
If txtUser.Text = DataRow.Item(0) And txtPassword.Text = DataRow(1) Then
If cmbAccountType.Text = DataRow(2) Then
connection.Close()
Return True
End If
End If
Next
Return False
End Function

Why are you opening the connection in the first place? You're not using it between the Open and Close calls so what's the point? The Fill method will automatically open the connection if it's currently closed and then it will automatically close it again if it opened it, i.e. Fill and Update will open the connection if necessary and then leave it in its original state afterwards. Get rid of both the Open and Close calls.

To begin with, Function's in vb.net require a DataType. I have no idea what da.Fill(dt) is doing in this function. If you didn't have an open connection you wouldn't be able to fill anything but then on the next line you open some unknown connection from somewhere.
OleDb pays no attention to the names of parameters. The position of the parameters in the sql string must match the order that the parameters are added to the parameters collection.
Here is one approach.
Private ConnStr As String = "Your connection string"
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
If Validation(txtUser.Text, txtPassword.Text, cmbAccountType.Text) Then
'Do something
End If
End Sub
Public Function Validation(UName As String, PWord As String, Type As String) As Boolean
Dim Count As Integer
Using cn As New OleDbConnection(ConnStr),
cmd As New OleDbCommand("Select Count(*) From SomeTable Where User = #User And Password = #Password And AccountType = #Type;", cn)
cmd.Parameters.Add("#User", OleDbType.VarChar).Value = UName
cmd.Parameters.Add("#Password", OleDbType.VarChar).Value = PWord
cmd.Parameters.Add("#Type", OleDbType.VarChar).Value = Type
cn.Open()
Count = CInt(cmd.ExecuteScalar)
End Using
If Count > 0 Then
Return True
End If
Return False
End Function
Of course you should NEVER store passwords as plain text.

Related

"No value given for one or more required parameters" error using OleDbCommand

I am trying to update a record in MS Access using VB.net. This code will be under the "Delivered" button. When I try to run it, it shows the "No value given for one or more required parameters" error. Here is my code:
Private Const strConn As String = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=C:\Users\Traicy\Downloads\MWL(11-30-2021)\MadeWithLove\MadeWithLove\MadeWithLove.mdb;"
ReadOnly conn As OleDbConnection = New OleDbConnection(strConn)
Dim cmd As OleDbCommand
Public Sub DeliveredUpdate()
Const SQL As String = "UPDATE DELIVERY SET delivery_status = #status"
cmd = New OleDbCommand(SQL, conn)
' Update parameter
cmd.Parameters.AddWithValue("#status", "Delivered")
' Open connection, update, then close connection
Try
conn.Open()
If cmd.ExecuteNonQuery() > 0 Then
MsgBox("The delivery status was successfully updated.")
End If
conn.Close()
Catch ex As Exception
MsgBox(ex.Message)
conn.Close()
End Try
End Sub
Do not declare connections or commands outside of the method where they are used. These database objects use unmanaged resources. They release these resources in their Dispose methods. The language provides Using blocks to handle this.
As mentioned in comments by Andrew Morton, you should have a Where clause to tell the database which record to update. This would contain the primary key of the record. I guessed at a name for the field, OrderID. Check your database for the real field name.
Access does not use named parameters but you can use names for readability. Access will be able to recognize the parameters as long as they are added to the Parameters collection in the same order that they appear in the sql string. In some databases the Add method is superior to AddWithValue because it doesn't leave the datatype to chance.
It is a good idea to separate your database code from your user interface code. If you want to show a message box in your Catch put the Try blocks in the UI code. This way your function can be used in a web app or mobile app without rewriting.
Public Function DeliveredUpdate(ID As Integer) As Integer
Dim recordsUpdated As Integer
Dim SQL As String = "UPDATE DELIVERY SET delivery_status = #status Where OrderID = #Id;"
Using conn As New OleDbConnection(strConn),
cmd As New OleDbCommand(SQL, conn)
cmd.Parameters.Add("#status", OleDbType.VarChar).Value = "Delivered"
cmd.Parameters.Add("#Id", OleDbType.Integer).Value = ID
conn.Open()
recordsUpdated = cmd.ExecuteNonQuery
End Using 'closes and disposes the command and connection
Return recordsUpdated
End Function
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim retVal As Integer
Dim id As Integer = 1 'not sure where you are getting this value from
Try
retVal = DeliveredUpdate(id)
Catch ex As Exception
MsgBox(ex.Message)
End Try
If retVal > 0 Then
MsgBox("The delivery status was successfully updated.")
End If
End Sub

ComboBox.SelectedText Property and Database Error

This specific code ComboBox2.SelectedItem query has an error to my database. I think I'm missing something with this code ComboBox2.SelectedItem:
Private Sub UpdateCombo()
ComboBox2.Items.Clear()
SQLcon.Open()
Dim Command As SqlClient.SqlCommand = SQLcon.CreateCommand()
Command.CommandText = "Select productName From tblProductsStocks"
Dim SQLReader As SqlClient.SqlDataReader = Command.ExecuteReader()
While SQLReader.Read()
ComboBox2.Items.Add(SQLReader.Item("productName"))
End While
SQLcon.Close()
End Sub
Private Sub ComboBox2_SelectedIndexChanged(sender As Object, e As EventArgs) Handles ComboBox2.SelectedIndexChanged
SQLcon.Open()
Dim Command As SqlClient.SqlCommand = SQLcon.CreateCommand()
Command.CommandText = "Select * From tblProductsStocks WHERE productName=" & ComboBox2.SelectedItem
Dim SQLReader As SqlClient.SqlDataReader = Command.ExecuteReader()
SQLReader.Read()
TextBox1.Text = SQLReader.Item("productType")
TextBox2.Text = SQLReader.Item("productMass")
SQLcon.Close()
End Sub
Please turn on Option Strict. This is a 2 part process. First for the current project - In Solution Explorer double click My Project. Choose Compile on the left. In the Option Strict drop-down select ON. Second for future projects - Go to the Tools Menu -> Options -> Projects and Solutions -> VB Defaults. In the Option Strict drop-down select ON. This will save you from bugs at runtime.
Connections need to be disposed as well as closed to be returned to the connection pool. If there is an error, your code may not even close the connection. If you keep your database objects local, you can control that they are closed and disposed. Using...End Using blocks take care of this for you even if there is an error. In my code the Command is part of the Using block. Note the comma after the connection constructor.
You can pass the connection string directly to the constructor of the connection. Likewise pass the command text and the connection to the command constructor.
Use parameters. Not only does it avoids errors concatenating strings but it also avoids Sql injection. In your code, the selected item is meant to be a string but you have failed to add the surrounding single quotes. This is not needed when you use parameters. Command text is executable code to the server and a malicious user can enter things that would ruin you database. Parameters are considered as values by the server, not executable code so they are much safer.
Open the connection at the last possible moment, right before the .Execute... Connections are precious resources and need to be opened, closed and disposed as quickly as possible. The connection must be open as long as the reader is engaged. So I moved updating the user interface (the text boxes) to outside the using block.
Private Sub ComboBox2_SelectedIndexChanged(sender As Object, e As EventArgs) Handles ComboBox2.SelectedIndexChanged
Dim String1 As String = ""
Dim String2 As String = ""
Using SQLcon As New SqlConnection("Your connection string"),
Command As New SqlCommand("Select * From tblProductsStocks WHERE productName= #producName", SQLcon)
'Check your database for the actual datatype and field size
Command.Parameters.Add("#productName", SqlDbType.VarChar, 100).Value = ComboBox2.SelectedItem.ToString
SQLcon.Open()
Dim SQLReader As SqlClient.SqlDataReader = Command.ExecuteReader()
SQLReader.Read()
String1 = SQLReader.Item("productType").ToString
String2 = SQLReader.Item("productMass").ToString
End Using 'closes and disposes the connection and command
TextBox1.Text = String1
TextBox2.Text = String2
End Sub

Self learning on vb.net

Currently I'm trying to understand and learn new code commands for vb.net. i have came across three codes while researching which is
"SELECT staff_id,pass_word FROM userlogin WHERE staff_id = #staff_id AND pass_word = #pass_word")
Second code:
Dim uName As New OleDbParameter("#staff_id", SqlDbType.VarChar)
Third and last:
uName.Value = txtstaffid.Text
myCommand.Parameters.Add(uName)
What are the uses of #pass_word code when you have already typed the pass_word column, Oledbparameter, and Parameters.Add?
The following code shows a bit more complete picture of what the code is doing. The Using...End Using blocks ensure that your objects are closed and disposed even if there are errors. Of course, in a real application, passwords would never be stored as plain text (too easy to hack). They would be salted and hashed but that is for another day.
Private Sub CheckPassword()
'This line assigns a Transact SQL command to a string variable.
'It will return a record with 2 columns. The #staff_id and #pass_word are parameter placeholders.
'The use of parameters limits the possibilit of SQL injection with malicious input be the user
'typing in the text box.
Dim strSQL = "SELECT staff_id,pass_word FROM userlogin WHERE staff_id = #staff_id AND pass_word = #pass_word;"
Using cn As New SqlConnection("Your connection string")
'Pass the command string and the connection to the constructor of the command.
Using cmd As New SqlCommand(strSQL, cn)
'It is unneccessary to create a command variable.
'The .Add method of the commands Parameters collection will create a parameter.
cmd.Parameters.Add("#staff_id", SqlDbType.VarChar).Value = txtstaffid.Text
cmd.Parameters.Add("#pass_word", SqlDbType.VarChar).Value = txtPassword.Text
cn.Open()
Using dr As SqlDataReader = cmd.ExecuteReader
'All we really need to know is whether we returned a row.
If dr.HasRows Then
MessageBox.Show("Login Successful")
Else
MessageBox.Show("Login Failed")
End If
End Using
End Using
End Using
End Sub

boolean web service method always returns true even when it should not

I have created a vb windows forms webservice in visual studio. I am having an issue where a boolean variable always returns true even when it should not. I am new to VB so it may just be a simple coding error but I just cannot figure it out.
Basically I have a sign in form, the user enters a username, from the form I pass the username to a function in the service called checkuser to see if the user exists in the DB. If the user does it exist it should go to another function to load existing data, if not it should call createuser function.
The variable should return true if user does exist and false if not. However when testing the program the variable always seems to return true even when I input a new username which does not exist.
Here is the form code(login form) which grabs the username and passes it to the checkUser function
Private Sub signInBtn_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles signInBtn.Click
If signInNick.Text = "" Then
MessageBox.Show("Please enter a user name")
signInNick.Focus()
Else
signinName = signInNick.Text
Dim check As Boolean
check = service.checkUser(signinName)
MessageBox.Show(check)
If check = False Then
main.Visible = True
Me.Hide()
main.tbxUserName.Text = signinName
MessageBox.Show("User has been created")
Else
main.Visible = True
Me.Hide()
main.tbxUserName.Text = signinName
MessageBox.Show("Thankyou for Signing In " + signinName)
End If
End If
End Sub
Here is the code for checkUser in the service
'Function to check if a user already exists in the database
<WebMethod()> _
Public Function checkUser(ByVal signinName As String) As Boolean
Dim userToCheck As String
Dim conn As New SqlConnection("Data Source=MARTIN-LAPTOP\SQLEXPRESS;Initial Catalog=musicPlaylist;Integrated Security=True")
Dim sql As String = "SELECT userNick FROM Users WHERE userNick = ('" & signinName & "')"
conn.Open()
Dim objcmd As New SqlCommand(sql, conn)
userToCheck = objcmd.ExecuteScalar()
If userToCheck = signinName Then
getExistingUserPLData(signinName)
Return True
Else
createUser(signinName)
Return False
End If
End Function
The check variable in the form code always seems to return true and this causes the service function to jump to getExistingUserPLData which does not create a user if the user is new.
The strange thing is if I do this through the webservice web page at http://localhost:50445/Service1.asmx, type in a brand new user name and invoke checkUser it will return false if the user does not exist and true if user does exist but it will not work and only return true if done through the form client.
Update: the code provided in one of the answers
If String.Equals(userToCheck, signinName, StringComparison.OrdinalIgnoreCase) Then
appears to work somewhat, as it appears the program is jumpiong to the createUser function if a new username is typed into the login box, but it is giving me an error at the createUser function
Voilation of primary key constraint, cannot insert duplicate key
here is the code for createUser
<WebMethod()> _
Public Function createUser(ByVal signinName As String) As String
Dim conn As New SqlConnection("Data Source=MARTIN-LAPTOP\SQLEXPRESS;Initial Catalog=musicPlaylist;Integrated Security=True")
Dim sql As String = "INSERT INTO Users (userNick) VALUES ('" & signinName & "')"
conn.Open()
Dim cmd As New SqlCommand(sql, conn)
Dim newUserName As String = cmd.ExecuteScalar()
conn.Close()
Return newUserName
End Function
It throws the error at Dim newUserName As String = cmd.ExecuteScalar()
The column userNick is a primary key but I dont understand why it says cannot isert duplicate key when the user does not exist in the database at all, I have checked the DB and username does not already exist, is my code completely wrong?
thanks for your help
Not sure if it is the cause, but your comparison of the username returned from the DB and the input value is case sensitive. When comparing strings, 99% of the time I prefer to use.
If String.Equals(userToCheck, signinName, StringComparison.OrdinalIgnoreCase) Then
'True
Else
'False
End If
Also, the line "signinName = signInNick.Text" is suspect as your code does not indicate what is happening here. Presumably it is a class scoped variable, however it could be a property that is not correctly implemented.
As a side, the line "If signInNick.Text = "" Then" would be better coded as:
If String.IsNullOrWhitespace(signInNick.Text) Then

how to keep a odbc connection open in vb.net

I'm trying to connect to a database and keep the connection open for any amount of user activity/queries within the database. Currently I have a connection that opens and closes for any query (save, update, etc...) which requires the logon process to the back-end every time the user saves etc... Is there a way to simply connect and leave the connection open so there won't be a lag time when running the query due to the logon process? This is what I'm using:
Private sConStrFormat As String = "Provider=TDOLEDB;Data Source=TDDEV;Persist Security Info=True;User ID={0};Password={1};Default Database=bcpm_ddbo;Session Mode=ANSI;"
Private Sub cmdsave_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles cmdsave.Click
Dim sSQL As String
Dim sConStr As String
Dim user As String
Dim pass As String
user = txtuser.Text
pass = txtpass.Text
Dim UserName As String = user
Dim Password As String = pass
sConStr = String.Format(sConStrFormat, UserName, Password)
Using Con As System.Data.OleDb.OleDbConnection = New System.Data.OleDb.OleDbConnection(sConStr)
Con.Open()
sSQL = "INSERT INTO LTC_FBS (CLM_NUM) VALUES ('" & Me.txtClaim.Text & "')"
Dim cmdins As New System.Data.OleDb.OleDbCommand(sSQL, Con)
cmdins.ExecuteNonQuery()
Con.Close()
End Using
End Sub
.Net automatically maintains a connection pool for you. According to MSDN, when you call Close() on the Connection the framework
releases the connection to the
connection pool, or closes the
connection if connection pooling is
disabled
In vb.net 4.5 do the following:
At the top straight after the class definer put in this line:
Public Shared conn As OdbcConnection
Then, in the subs where you want to use the connection use this line:
If conn Is Nothing Then conn = New OdbcConnection(<your_connection_string>): conn.Open()
Then the New OdbcCommand will use the existing connection without opening a new one. Don't close the connection in your script until you are quite certain you're finished with it (_Shutdown is a good spot and you're good to go.
This also solves problems with MySQL when constantly opening new connections causes the max connections error.
Instead of defining 'con' in the using statement, define it up above as a static variable. When the function is called, you can see if 'Con' has been assined or not. If not, you build your connection string and set Con = New OleDBConnection, and open it. Since it's a static variable, it will retain its value at the next call. Check that it's not nothing, and then use it right away. Make sure you don't call close in the routine or the connection will not remain open.