Close connection if there is an error 'connection not closed'? - vb.net

My vb.net application shows an error.
Connection not closed. Connection's current state is open
Here is my code. Please help me rectify the error:
Private Sub saveBtn_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles saveBtn.Click
addSubject()
End Sub
Private Function addSubject() As Boolean
Dim cmd As New SqlCommand
Dim ok As Boolean = False
cmd.Connection = con
cmd.CommandText = " INSERT INTO Subjects(subject_name) VALUES(#inn)"
cmd.CommandType = CommandType.Text
cmd.Parameters.AddWithValue("inn", subjectTxt.Text)
Try
con.Open()
cmd.ExecuteNonQuery()
ok = True
Catch ex As Exception
MessageBox.Show(ex.Message, "Add failed")
ok = False
End Try
cmd.Dispose()
con.Close()
Return ok
con.Close()
End Function

There might be an open connection in your previous codes in which you were not able to close it.
This connection state checker could help you:
If connection.State <> 1
connection.Open()
End IF

wrap sqlcommand in a using statement. Don't call close or dispose manually.

Try to check connection state before opening, no need to open connection if it has already opened :
If con.State <> ConnectionState.Open Then
con.Open()
End If
That will help you avoid current exception.
Anyway, root cause of this problem could be somewhere else. Because, your code already tried to close connection in the end, so it seems that there is another part of your program that is not closing the connection properly.
Possible solution is not to share your connection object, instantiate new connection every time needed and wrap it around using statement as also pointed by #DeveloperGuo.

Related

UPDATE Button not working in VB . and no error is showing [closed]

Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
Closed 3 years ago.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
This question was caused by a typo or a problem that can no longer be reproduced. While similar questions may be on-topic here, this one was resolved in a way less likely to help future readers.
Improve this question
Private Sub btnHREmployeeInfoUpdate_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnHREmployeeInfoUpdate.Click
provider = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source="
datafile = "C:\Users\Asus\Documents\Visual Studio 2008\Projects\WindowsApplication7\WindowsApplication7\Tea.accdb"
connString = provider & datafile
myconnection.ConnectionString = connString
'to update employee status ' not working
myconnection.Open()
Dim str As String
str = "update[HR_Employee_Details]set[Status]='" & cboHREmployeeInfoStatus.Text & "'Where[EmployeeID]='" & txtHREmployeeInfoNewEmployeeID.Text & "'"
Dim cmd As OleDbCommand = New OleDbCommand(str, myconnection)
Try
cmd.ExecuteNonQuery()
Catch ex As Exception
MsgBox("not updated", MsgBoxStyle.OkOnly, "Update fail")
End Try
MsgBox("Updated!", MsgBoxStyle.OkOnly, "Updated")
myconnection.Close()
End Sub
There are some really bad patterns in that code, and as so often happens just updating the code to use better practice will help find the underlying problem. You'll need to read the comments below to see exactly how:
'Isolate and group the DB access in it's own class, module, or class library.
'ALL access to the database in the application should run through here.
Public Module DB
'Move these out of the individual methods, so you don't
'have to repeat them everywhere
Private Readonly Property provider As String = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source="
Private Readonly Property datafile As String = "C:\Users\Asus\Documents\Visual Studio 2008\Projects\WindowsApplication7\WindowsApplication7\Tea.accdb"
Private Readonly Property connString As String = provider & datafile
'Each query gets its own public method in this module,
'but everything else should be marked Private
Public Sub UpdateEmployeeStatus(NewStatus As String, EmployeeID As Integer)
'Ole provider for ADO.Net uses ? As parameter placeholders.
'This string could be a CONSTANT!
Dim sql As String = "UPDATE [HR_Employee_Details] SET [Status]= ? WHERE [EmployeeID]= ?"
'The Using block will guarantee your connection is
'closed, even if an exception is thrown.
'The old code could have leaked connection objects
'when there were exceptions.
'Also, ADO.Net works **much** better when you
'create new connection objects for most queries.
Using conn As New OleDbConnection(connString), _
cmd As New OleDbCommand(sql, conn)
'I have to guess at parameter types here.
'You should change this to use exact types &
'lengths from the database.
'ADO.Net will figure out what value goes to
'what parameter based on the order of the
'placeholders in the sql string.
'These parameters are the ONLY correct
'way to include data in an sql command.
'Anything else leaves you open to sql injection.
cmd.Parameters.Add("?", OleDbType.VarWChar, 20).Value = NewStatus
'If this is not an integer, change it to correct type.
'But I wanted to be sure to show two different
'parameter types
cmd.Parameters.Add("?", OleDbType.Integer).Value = EmployeeID
'wait as long as possible to call Open
conn.Open()
cmd.ExecuteNonQuery()
End Using 'No need to call conn.Close() -- the Using block took care of it
End Sub
End Module
Private Sub btnHREmployeeInfoUpdate_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnHREmployeeInfoUpdate.Click
'Exception handling can still live in the UI
Try
'Again: integer here is just to demonstrate a
'different parameter type.
'If your employee IDs really are strings, it's
'easy to remove this.
Dim EmployeeID As Integer = Integer.Parse(txtHREmployeeInfoNewEmployeeID.Text)
DB.UpdateEmployeeStatus(cboHREmployeeInfoStatus.Text, EmployeeID)
MsgBox("Updated!", MsgBoxStyle.OkOnly, "Updated")
Catch ex As Exception
'This is where your real problem was!
'This catch block hid the detail from the exception
'you would need to solve the problem!
'If you don't want to show this to the user, which
'is reasonable, you can at least log it somewhere.
'Once you see the exception message, it will probably
'be much clearer how to fix the issue.
MsgBox($"Error updating the database:{vbCrLf}{Ex.Message}", MsgBoxStyle.OkOnly, "Not Updated")
End Try
End Sub
But so you don't feel like the "good" code needs to be so much longer, here it is again with the comments removed. Especially note how clean the event handler method has become.
Public Module DB
Private Readonly Property provider As String = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source="
Private Readonly Property datafile As String = "C:\Users\Asus\Documents\Visual Studio 2008\Projects\WindowsApplication7\WindowsApplication7\Tea.accdb"
Private Readonly Property connString As String = provider & datafile
Public Sub UpdateEmployeeStatus(NewStatus As String, EmployeeID As Integer)
Dim sql As String = "UPDATE [HR_Employee_Details] SET [Status]= ? WHERE [EmployeeID]= ?"
Using conn As New OleDbConnection(connString), _
cmd As New OleDbCommand(sql, conn)
cmd.Parameters.Add("?", OleDbType.VarWChar, 20).Value = NewStatus
cmd.Parameters.Add("?", OleDbType.Integer).Value = EmployeeID
conn.Open()
cmd.ExecuteNonQuery()
End Using
End Sub
End Module
Private Sub btnHREmployeeInfoUpdate_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnHREmployeeInfoUpdate.Click
Try
Dim EmployeeID As Integer = Integer.Parse(txtHREmployeeInfoNewEmployeeID.Text)
DB.UpdateEmployeeStatus(cboHREmployeeInfoStatus.Text, EmployeeID)
MsgBox("Updated!", MsgBoxStyle.OkOnly, "Updated")
Catch ex As Exception
MsgBox($"Error updating the database:{vbCrLf}{Ex.Message}", MsgBoxStyle.OkOnly, "Not Updated")
End Try
End Sub

How to create a txt file that records login details? VB.NET

I wanna create a txt file that stores the Username, Password, Date & Time, and User Type when "Log In" button is pressed. But all I know is how to create a txt file. Can anyone help me? Here's my code for my Log In button:
Private Sub btnLogin_Click(sender As Object, e As EventArgs) Handles btnLogin.Click
Dim username As String = ""
Dim password As String = ""
Dim cn As New OleDbConnection("Provider=Microsoft.ACE.OLEDB.12.0;" & "Data Source=D:\Library Management System\LMS_Database.accdb")
Dim cmd As OleDbCommand = New OleDbCommand("SELECT ID_Number FROM Users WHERE ID_Number = '" & txtUsername.Text & "' AND ID_Number = '" & txtPassword.Text & "'", cn)
cn.Open()
Dim dr As OleDbDataReader = cmd.ExecuteReader()
If (dr.Read() = True And cboUserType.Text = "Student") Then
MsgBox("Welcome!", MsgBoxStyle.OkOnly, "Successfully logged in.")
frmViewBooks.Show()
txtUsername.Clear()
txtPassword.Clear()
cboUserType.SelectedIndex = -1
Me.Hide()
Else
If (txtUsername.Text = "admin" And txtPassword.Text = "ckclibraryadmin" And cboUserType.Text = "Administrator") Then
MsgBox("Welcome, admin!", MsgBoxStyle.OkOnly, "Successfully logged in.")
frmAdminWindow.Show()
txtUsername.Clear()
txtPassword.Clear()
cboUserType.SelectedIndex = -1
Me.Hide()
Else
MsgBox("Your username or password is invalid. Please try again.", MsgBoxStyle.OkOnly, "Login failed.")
txtUsername.Clear()
txtPassword.Clear()
cboUserType.SelectedIndex = -1
End If
End If
End Sub
I'd be getting the Date and Time value from my timer.
Private Sub frmLogIn_Load(sender As Object, e As EventArgs) Handles MyBase.Load
tmrLogIn.Start()
End Sub
Private Sub tmrLogIn_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles tmrLogIn.Tick
lblTime.Text = DateTime.Now.ToString()
End Sub
Thank you!
There are a few things that I'd like to point out to maybe help you later on down the road. Data object generally implement iDisposable, it is a good idea to either wrap them in Using statements or dispose of them manually. Also, it is generally a good idea to wrap any database code into a Try/Catch exception handler because something can go wrong at any point you're trying to access outside data. Also, it is always a good idea to parameterize your query. Finally, you are only wanting to validate that a row is returned from your SQL statement, so your SQL statement should instead return the number of rows returned and then you can use the ExecuteScalar to get that one value returned.
With all of that out of the way, all you would need to do is append a line to a text file using the IO.File.AppendAllLines method using the data you already have if the login was validated.
Here is an example of implementing everything I suggested:
'Declare the object to return
Dim count As Integer = -1
'Declare the connection object
Dim con As OleDbConnection
'Wrap code in Try/Catch
Try
'Set the connection object to a new instance
con = New OleDbConnection("Provider=Microsoft.ACE.OLEDB.12.0;" & "Data Source=D:\Library Management System\LMS_Database.accdb")
'Create a new instance of the command object
'TODO: If [Username] and [Password] are not valid columns, then change them
Using cmd As OleDbCommand = New OleDbCommand("SELECT Count([ID_Number]) FROM [Users] WHERE [Username] = #username AND [Password] = #password", con)
'Parameterize the query
With cmd.Parameters
.AddWithValue("#username", txtUsername.Text)
.AddWithValue("#password", txtPassword.Text)
End With
'Open the connection
con.Open()
'Use ExecuteScalar to return a single value
count = Convert.ToInt32(cmd.ExecuteScalar())
'Close the connection
con.Close()
End Using
If count > 0 Then
'Append the data to the text file
'TODO: Change myfilehere.txt to the desired file name and location
IO.File.AppendAllLines("myfilehere.txt", String.Join(",", {txtUsername.Text, txtPassword.Text, DateTime.Now, cboUserType.Text}))
'Check if it is a student or admin
If cboUserType.Text = "Student" Then
'Inform the user of the successfull login
MessageBox.Show("Welcome!", "Login Successfull", MessageBoxButtons.OK)
frmViewBooks.Show()
ElseIf cboUserType.Text = "Administrator" Then
'Inform the admin of the successfull login
MessageBox.Show("Welcome, admin!", "Login Successfull", MessageBoxButtons.OK)
frmAdminWindow.Show()
End If
'Reset and hide the form
txtUsername.Clear()
txtPassword.Clear()
cboUserType.SelectedIndex = -1
Me.Hi
Else
'Inform the user of the invalid login
MessageBox.Show("Invalid username and/or password. Please try again.", "Invalid Login", MessageBoxButtons.OK)
End If
Catch ex As Exception
'Display the error
Console.WriteLine(ex.Message)
Finally
'Check if the connection object was initialized
If con IsNot Nothing Then
If con.State = ConnectionState.Open Then
'Close the connection if it was left open(exception thrown)
con.Close()
End If
'Dispose of the connection object
con.Dispose()
End If
End Try
Your goal can be achieved in many ways.For example,you can create an access/sql/mysql database to store the required information.But if u want to use a textfile instead,you can store Username,password and other details on seperate lines.Then you can read each line from the text file and use it the way you want.So,which one u prefer? a database or text file? leave a comment and i'lll add the codes/instructions depending on your choice

VB.Net - Inserting data to Access Database using OleDb

Can you please tell me what's wrong with the code I'm using? Everytime I execute this, it throws the exception (Failed to connect to database)
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim conn As New System.Data.OleDb.OleDbConnection()
conn.ConnectionString = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=|DataDirectory|\socnet.accdb"
Dim sql As String = String.Format("INSERT INTO login VALUES('{username}','{password}','{secques}','{secans}')", txt_username.Text, txt_passwd.Text, txt_secquestion.Text, txt_secansw.Text)
Dim sqlCom As New System.Data.OleDb.OleDbCommand(sql)
'Open Database Connection
sqlCom.Connection = conn
conn.Open()
Dim icount As Integer = sqlCom.ExecuteNonQuery
MessageBox.Show(icount)
MessageBox.Show("Successfully registered..", "Success", MessageBoxButtons.OK, MessageBoxIcon.Error)
Catch ex As Exception
MessageBox.Show("Failed to connect to Database..", "Database Connection Error", MessageBoxButtons.OK, MessageBoxIcon.Error)
End Try
cmd_submit2_Click(sender, e)
End If
End Sub
I am using Access 2013 and VS 2015 Community, if that helps. Thank you.
You should use a parameterized approach to your commands.
A parameterized query removes the possibility of Sql Injection and you will not get errors if your string values are not correctly formatted.
Note that if you don't do anything in the exception block then it is better to remove it and let the exception show itself or at least show the Exception.Message value, so you are informed of the actual error.
Finally every disposable object should be created with the Using statement that ensures a proper close and dispose of such objects (in particular the OleDbConnection)
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim sql As String = "INSERT INTO login VALUES(#name, #pass, #sec, #sw)"
Using conn = New System.Data.OleDb.OleDbConnection("Provider=Microsoft.ACE.OLEDB.12.0;Data Source=|DataDirectory|\socnet.accdb")
Using sqlCom = New System.Data.OleDb.OleDbCommand(sql, conn)
conn.Open()
sqlCom.Parameters.Add("#name", OleDbType.VarWChar).Value = txt_username.Text
sqlCom.Parameters.Add("#pass", OleDbType.VarWChar).Value = txt_passwd.Text
sqlCom.Parameters.Add("#sec", OleDbType.VarWChar).Value = txt_secquestion.Text
sqlCom.Parameters.Add("#sw", OleDbType.VarWChar).Value = txt_secansw.Text
Dim icount As Integer = sqlCom.ExecuteNonQuery
End Using
End Using
End Sub
Keep in mind that omitting the field names in the INSERT INTO statement requires that you provide values for every field present in the login table and in the exact order expected by the table (So it is better to insert the field names)
For example, if your table has only the 4 known fields:
Dim sql As String = "INSERT INTO login (username, userpass, secfield, secfieldsw) " & _
"VALUES(#name, #pass, #sec, #sw)"

Datagridview doesn't clear or replace the previos data vb.net

Can't find the way to replace the previous data with the new one....
I use a button to view my table in dgv. When I click the button twice for viewing my table it only show the data next with the previous one
Here's the code that I'm using
Private Sub cmdview_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles cmdview.Click
connetionstring = "Integrated Security = SSPI; data source= DELL-PC;Initial catalog=Library System"
connection = New SqlConnection(connetionstring)
sql = "select * from dbo.tblbook"
Try
connection.Open()
adapter = New SqlDataAdapter(sql, connection)
adapter.Fill(ds)
connection.Close()
dtg1.DataSource = ds.Tables(0)
Return
Catch ex As Exception
MsgBox(ex.ToString)
End Try
End Sub
http://msdn.microsoft.com/en-us/library/bh8kx08z.aspx
"Tables and columns are only created if they do not already exist; otherwise Fill uses the existing DataSet schema. "
Meaning if you have data in your dataset it will not be overwritten if you use fill. So try this before your adapter.Fill line:
ds.Clear()

Subroutine not firing

I have the following subroutines:
Private Sub Exceptionquery()
Dim connection As System.Data.SqlClient.SqlConnection
Dim connectionString As String = "Initial Catalog=mdr;Data Source=xxxxx;uid=xxxxx;password=xxxxx"
Dim _sql As String = "SELECT [Exceptions].Employeenumber,[Exceptions].exceptiondate, [Exceptions].starttime, [exceptions].endtime, [Exceptions].code, datediff(minute, starttime, endtime) as duration INTO scratchpad3 " + _
"FROM [Exceptions]" + _
"where [Exceptions].exceptiondate between #payperiodstartdate and payperiodenddate" + _
"GROUP BY [Exceptions].Employeenumber, [Exceptions].Exceptiondate, [Exceptions].starttime, [exceptions].endtime," + _
"[Exceptions].code, [Exceptions].exceptiondate"
connection = New SqlConnection(connectionString)
connection.Open()
Dim _CMD As SqlCommand = New SqlCommand(_sql, connection)
_CMD.Parameters.AddWithValue("#payperiodstartdate", payperiodstartdate)
_CMD.Parameters.AddWithValue("#payperiodenddate", payperiodenddate)
connection.Close()
End Sub
Public Sub exceptionsButton_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles exceptionsButton.Click
Exceptionquery()
Dim connection As System.Data.SqlClient.SqlConnection
Dim adapter As System.Data.SqlClient.SqlDataAdapter = New System.Data.SqlClient.SqlDataAdapter
Dim connectionString As String = "Initial Catalog=mdr;Data Source=xxxxx;uid=xxxxx;password=xxxxx"
Dim ds As New DataSet
Dim _sql As String = "SELECT * from scratchpad3"
connection = New SqlConnection(connectionString)
connection.Open()
Dim _CMD As SqlCommand = New SqlCommand(_sql, connection)
_CMD.Parameters.AddWithValue("#payperiodstartdate", payperiodstartdate)
_CMD.Parameters.AddWithValue("#payperiodenddate", payperiodenddate)
adapter.SelectCommand = _CMD
Try
adapter.Fill(ds)
If ds Is Nothing OrElse ds.Tables.Count = 0 OrElse ds.Tables(0).Rows.Count = 0 Then
'it's empty
MessageBox.Show("There was no data for this time period. Press Ok to continue", "No Data")
connection.Close()
Exceptions.saveButton.Enabled = False
Exceptions.Show()
Else
connection.Close()
Exceptions.Show()
End If
Catch ex As Exception
MessageBox.Show(ex.ToString)
connection.Close()
End Try
End Sub
and when I press the button:
Public Sub exceptionsButton_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles exceptionsButton.Click
My subroutine Exceptionquery is not being fired. I know that it's probably something simple that I'm overlooking but don't know what it is. Can someone please assist me with this?
Thank you
Are you sure ExceptionQuery() is being run from exceptionsButton_Click? Your example as shown should work. Step through with the debugger and verify that your button event is actually firing.
it should work, check if the event handler exceptionsButton_Click is called at all and see with a breakpoint if the execution gets into it.
P.S. a small very important detail: the way you are handling the connection is not optimal, you can use a using block, something like this:
using (dim connection as New SqlConnection(connectionString)
...
in this way you are sure connection is closed and disposed when running out of scope and you do not need all those connection.close in the if/else and catch which are wrong anyway the way you did it so far, because if the connection has been closed and you enter the catch and try to close it again, there will be another error.