I get a System.InvalidOperationException with the additional Info saying that there is an unclosed Datareader in this line.
MyCmd.ExecuteNonQuery()
MyCmd is a Private variable accessible for all subs and is declared as
MyCmd = New OleDb.OleDbCommand()
MyCmd.CommandText = "Insert Into Netzwerkverwaltung(NSub, Nip, Npc, Nuser, Pherst, Pser, Pmod, Pcpu, Phdd, Pram, Pkauf, Sos, Sosoem, Sosopen, Sfunk, Soffice, Sofficeoem, Sofficeopen, Anmerkung) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?);"
MyCmd.Connection = MyCon
After this the parameters are added.
I use MyCon in a Sub before with a Datareader but the Datareader is closed when I debug it but it still doesn't work.
Dim myDR As OleDb.OleDbDataReader
MyCmd = New OleDb.OleDbCommand("SELECT * FROM Netzwerkverwaltung WHERE ID=?", MyCon)
MyCmd.Parameters.Add(New System.Data.OleDb.OleDbParameter("ID", System.Data.OleDb.OleDbType.Integer))
MyCmd.Parameters("ID").Value = Request("ID")
If MyCon.State = ConnectionState.Closed Then
MyCon.Open()
End If
myDR = MyCmd.ExecuteReader()
There I implement the Datareader and close it later on, and it is closed, I double checked that.
This code worked perfectly fine in VS2010 BTW. And I am working with VS2015 right now.
If you're getting an error message telling you that there is a data reader open on that connection then there almost certainly is. This is why you should always use Using blocks for short-lived, disposable objects, e.g.
Using myDataReader = myCommand.ExecuteReader()
'Use myDataReader here.'
End Using
The reader will be implicitly closed at the End Using line so you can't accidentally leave it open. Depending on specifics, you should probably be doing the same thing with your connection too.
Related
I have a table for user screens.
UserID - ScreenID - Perm
I need to hide controls when the form opens with UserID and ScreenID, and I can't use the loop with condition.
This is my code:
Try
Dim da As New SqlDataAdapter
Dim ds As New DataSet
If dbconnect.State = ConnectionState.Closed Then dbconnect.Open()
da = New SqlDataAdapter("SELECT * FROM UserScreens WHERE UserID='" & UserID & "'", dbconnect)
da.Fill(ds, "Table")
If ds.Tables(0).Rows.Count > 0 Then
Dim M As DataRow = ds.Tables(0).Rows(0)
For Each ctrl As Control In Ribbon1.Controls
ctrl.Visible = M.Item("Perm")
Next
'DocIDtxt.Text = M.Item("DOCID")
End If
Catch ex As Exception
If dbconnect.State = ConnectionState.Open Then dbconnect.Close()
MsgBox(ex.ToString)
End Try
I always worry about connections first. From MS docs
"The IDbConnection object associated with the select command must be valid, but it does not need to be open. If the IDbConnection is closed before Fill is called, it is opened to retrieve data, then closed. If the connection is open before Fill is called, it remains open."
What that means is you opened your connection before the .Fill method so it will remain open. Bad! The only way your code closes the connection is if there is an error. A Finally section with .Close in your Try...End Try would do the trick but better yet use Using...End Using. This block will ensure that your objects are closed and disposed properly even if there is an error. When an object has a Dispose method it may have unmanaged resources that it must clean up.
Next, turn on Option Strict. It will be a great help pointing potential runtime errors.
Third, always use Parameters.
See inline explanation and comments.
Private Sub OpCode()
Try
'A DataTable does not have a Dispose() method so it will fall
'out of scope and be garbage collected.
Dim dt As New DataTable
'SqlConnection has a Dispose() method so use Using
Using cn As New SqlConnection("Your connection string")
'SqlCommand has a Dispose() method so use Using
Using cmd As New SqlCommand("SELECT * FROM UserScreens WHERE UserID= #UserID", cn)
'Always use Parameters. Never concatenate strings in SQL statements.
cmd.Parameters.Add("#UserID", SqlDbType.VarChar).Value = UserID
cn.Open()
'SqlDataReader has a Dispose() method so use Using
Using dr As SqlDataReader = cmd.ExecuteReader
dt.Load(dr)
End Using
End Using
End Using
If dt.Rows.Count > 0 Then
Dim M As DataRow = dt.Rows(0)
For Each ctrl As Control In Ribbon1.Controls
'If Perm is not a boolean this line of code can't work
ctrl.Visible = CBool(M.Item("Perm"))
Next
'DocIDtxt.Text = M.Item("DOCID")
End If
Catch ex As Exception
MsgBox(ex.ToString)
End Try
End Sub
Have already looked questions similar to mine but none of them works for me this is my code
dbconn = New SqlConnection
dbconn.ConnectionString = ("Data Source=JENELIE\SQLEXPRESS;Initial Catalog=feeding_monitoring_system;User ID=sa;Password=Jenelie19; MultipleActiveResultSets = true")
Dim reader As SqlDataReader
Dim sda As New SqlDataAdapter
Dim ds As New DataSet()
Try
dbconn.Open()
Dim sql As String
sql = "select Count (Gender) as NumberofStudent, Gender from Student_Info Group by Gender"
dbcomm = New SqlCommand(sql, dbconn)
reader = dbcomm.ExecuteReader
sda.SelectCommand = dbcomm
sda.Fill(ds, "Student_Info")
Catch ex As SqlException
MessageBox.Show(ex.Message)
Finally
dbconn.Dispose()
End Try
Then at sda.Fill(ds, "Student_Info") an error happens
You dont use that reader at all, so i don't understand your code. You want to fill the DataSet with the DataAdapter, then this is needed (always use Using):
Dim ds As New DataSet()
Using dbconn As New SqlConnection("Data Source=JENELIE\SQLEXPRESS;Initial Catalog=feeding_monitoring_system;User ID=sa;Password=Jenelie19;MultipleActiveResultSets = true")
Dim sda = New SqlDataAdapter("select Count (Gender) as NumberofStudent, Gender from Student_Info Group by Gender", dbconn)
Try
sda.Fill(ds, "Student_Info") ' you dont need to open/close the connection
Catch ex As SqlException
MessageBox.Show(ex.Message)
End Try
End Using
I would try making sure that all disposable objects are properly disposed within this function. I recommend the Using statement to help ensure that any disposable object gets properly disposed as it goes out of scope. I believe that SqlConnection, SqlDataReader, SqlDataAdapter and DataSet are all disposable.
Edit: Although I think Tim's answer is more targeted at your problem (the SqlDataReader is unused and unnecessary), you should make sure to clean-up all your disposable objects, too. If you do use an SqlDataReader, you'll want to dispose of it before doing anything else, unless you're just trying to prove that you can have multiple result sets open at once, in which case, the lack of cleanup in multiple accesses to the same connection might be responsible (if one of them doesn't include MultipleActiveResultSets).
First off, in that situation, you do not need to use reader, you just need SQLDataAdapter.
Second, you should use Conn.Close() to close your SQL connection, rather than Conn.Dispose(). The error means that some where in your code, you opened the connection before hand, but never closed it.
When executing multiple queries what is the best practice when using Commands and DataReaders? is it best to create only one and dispose/close it before using again or create a new one everytime and dispose/close that one? For example...
Dim sqlcmd as SqlCommand
Dim sqldr as SqlDatareader
sqlcmd = new SqlCommand(Query here, connection)
sqldr = sqlcmd.ExecuteReader
'Do stuff
sqlcmd.Dispose()
sqldr.Close()
sqlcmd = new SqlCommand(Different Query here, connection)
sqlcmd.ExecuteNonQuery
'Do stuff
sqlcmd.Dispose()
'And so on
Or
Dim sqlcmd as SqlCommand = new SqlCommand(Query here, connection)
Dim sqldr as SqlDataReader = sqlcmd.ExecuteReader
'Do stuff
sqlcmd.Dispose()
sqldr.Close()
Dim anothersqlcmd as SqlCommand = new SqlCommand(Different Query here, connection)
anothersqlcmd.ExecuteNonQuery
'Do stuff
anothersqlcmd.Dispose()
'And so on
Sorry about the example, i'm aware of the using statement but my example is the same. Is it better to be just using 1 Command and DataReader or creating a new one everytime?
I think regardless the allocation is there, for readability sake I would go with option two to identify when I have a new command with different parameters
In your example, it doesn't matter. They are both the same. But in your sample 2 you have a bug by calling sqlcmd.ExecuteNonQuery.
I personally would put them in two separate method and call the method instead. Just make sure the connection object is open only when needed and close is right away when not needed.
This is just what I do, not necessarily Best Practices but I am very careful to close my connections and dispose of my objects.
cn.Open()
If Mode = "Add" Then
cmd.CommandText = "InsertVendor"
RetVal = cmd.ExecuteNonQuery
Else 'Update
cmd.Parameters.Add("#ID", SqlDbType.Int).Value = itgID
cmd.CommandText = "UpdateVendors"
RetVal = cmd.ExecuteNonQuery
End If
cn.Close()
cmd.Dispose()
Here, I used one command object but tailored it for 2 different operations. To get everything cleaned up I use Try..Catch..Finally
Finally
If Not IsNothing(cmd) Then
cmd.Dispose()
End If
If cn.State = ConnectionState.Open Then
cn.Close()
End If
End Try
Then check on the state of my objects there. There should never be an exception in a Finally block. I do use the same connection object throughout my DataAccess Class. Be careful of the DataReader; don't close your connection until it has finished its work.
I'm having a problem in project of mine in VB.NET. The problem is whenever I want to save, delete or update data with an Access database I get an error with a message saying that "not allowed to change the connection string property. connection's current state is open".
I have used If con.State = ConnectionState.Open Then con.Close() End If
command using finally in every section where I have called the database.
But still I'm having the same problem. What am I doing wrong?
Use the "USING"-Keyword. Exiting a using block calls .Dispose() on the object which for a SqlConnection will close the connection and any open resources.
Using connection As New SqlConnection(connection)
Dim command As New SqlCommand("Select * From dbo.table1",connection)
command.ExecuteNonQuery()
End Using
EDIT:
Module Module1
Public Sub DbConnection()
Dim connectionString as String = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=yourServerAddress;Initial Catalog=university.mdb;
Integrated Security=SSPI;"
Using connection as New Sqlconnection(connectionstring)
Dim command As New SqlCommand("Select * From dbo.table1",connection)
command.ExecuteNonQuery()
End Using
End Sub
End Module
Should I use using?
Private Sub btntest_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btntest.Click
If sqlConnection.State = ConnectionState.Closed Then
sqlConnection.Open()
End If
Dim query = "Select * from tablebusiness"
Dim cmd = New MySqlCommand(query, sqlConnection)
Dim data = cmd.ExecuteReader()
Do While data.Read
Loop
Dim cmd1 = New MySqlCommand(query, sqlConnection)
Dim data1 = cmd1.ExecuteReader //Error. Already have data reader
//Error There is already an open DataReader associated with this Connection which must be closed first.
Dim check = 1
'sqlConnection.Close()
End Sub
Although you have not let us know what the error is (which makes solving any problem much harder), I expect the issue is arising because you are trying to re-use the SqlConnection object for 2 different commands. Especially since you are not disposing your first command before initialising the second.
Firstly, use 2 different SqlConnection objects to manage the connection to the database. You are not putting any more overhead on the database or the code if you do this. Let the .NET framework connection pooling do its job - don't try to do it yourself. You don't need to do anything specific to enable connection pooling (although you can disable it by setting Pooling=false in your connection string).
Secondly use the using statement to correctly dispose your SqlConnection, SqlCommand, and SqlDataReader objects. e.g.
Using connection As New SqlConnection(connectionString)
connection.Open()
Using Command As New SqlCommand(query, connection)
Using reader As SqlDataReader = Command.ExecuteReader()
While reader.Read()
'Do Stuff'
End While
End Using
End Using
connection.Close()
End Using
You have missed the parenthesis after cmd1.ExecuteReader. It should be cmd1.ExecuteReader().
You Need another Conncetion if you want both the datareaders to work simultaneously, else close/ dispose the previous command before using cmd1.ExecuteReader()