Closing SqlConnection without Closing SQL reader - can it cause connection Leak - vb.net

I have been using SQLDataReader for fetchig some data from a db. Once I used Reader with the the connection I am closing the connection only and not the Reader. Do we have any possibility of connection leak
Here is the code that I am using
Public Sub Get_SomeData(ByVal sCon As String,ByRef ObjectToReturn As SomeClass)
Dim sqlCon As SqlConnection = New SqlConnection(sCon)
Dim sqlR As SqlDataReader = Nothing
Dim sqlCmd As SqlCommand = New SqlCommand
sqlCmd.CommandType = CommandType.StoredProcedure
sqlCmd.Connection = sqlCon
sqlCmd.CommandText = "get_SomeData"
sqlCon.Open()
sqlR = sqlCmd.ExecuteReader(CommandBehavior.CloseConnection)
If sqlR.HasRows And sqlR.Read Then
ObjectToReturn.Property1 = sqlR("Column1").ToString
ObjectToReturn.Property1 = sqlR("Column1").ToString
ObjectToReturn.Property1 = sqlR("Column1").ToString
ObjectToReturn.Property1 = sqlR("Column1").ToString
End If
sqlCon.Close()
End Sub

No, closing the connection will suffice, but a better approach is through the Using statement
Using sqlCon = New SqlConnection(sCon)
Dim sqlR As SqlDataReader = Nothing
Using sqlCmd = New SqlCommand
sqlCmd.CommandType = CommandType.StoredProcedure
sqlCmd.Connection = sqlCon
sqlCmd.CommandText = "get_SomeData"
sqlCon.Open()
Using sqlR = sqlCmd.ExecuteReader()
If sqlR.HasRows And sqlR.Read Then
ObjectToReturn.Property1 = sqlR("Column1").ToString
.......
End If
End Using
End Using
End Using
The important part in MSDN docs about Using
Sometimes your code requires an unmanaged resource, such as a file
handle, a COM wrapper, or a SQL connection. A Using block guarantees
the disposal of one or more such resources when your code is finished
with them. This makes them available for other code to use.
Managed resources are disposed of by the .NET Framework garbage
collector (GC) without any extra coding on your part. You do not need
a Using block for managed resources. However, you can still use a
Using block to force the disposal of a managed resource instead of
waiting for the garbage collector.

Related

Best practice when executing multiple queries

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.

OleDbCommand unclosed Datareader Error

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.

Getting Timeout expire error using data reader

Using VB.Net and SQL
Code
myConnection = New SqlConnection(Connection)
myConnection.Open()
Dim myCommand As SqlCommand = New SqlCommand("proc_g_report", myConnection)
Dim myReader As SqlDataReader = myCommand.ExecuteReader()
DTResults.Load(myReader)
Throwing error as "Timeout expired. The timeout period elapsed prior to completion of the operation or the server is not responding"
Error on this line Dim myReader As SqlDataReader = myCommand.ExecuteReader()
And I cannot change the database pool size due to security reason, Please any one advise.
Try Setting CommandTimeout
myConnection = New SqlConnection(Connection)
myConnection.Open()
Dim myCommand As SqlCommand = New SqlCommand("proc_g_report", myConnection)
myCommand.CommandTimeout=0
Dim myReader As SqlDataReader = myCommand.ExecuteReader()
DTResults.Load(myReader)
The error seems to be unrelated but, if you want to call the execution of a stored procedure you need to tell what is the CommandType passed.
The default is CommandType = CommandType.Text, so your command text (proc_g_report) is treated as if it was a SELECT/INSERT or other standard T-SQL statement.
You need to set the CommandType and possibly add the Using Statement around the disposable objects....
Using myConnection = New SqlConnection(Connection)
Using myCommand = New SqlCommand("proc_g_report", myConnection)
myCommand.CommandType = CommandType.StoredProcedure
myConnection.Open()
Using myReader = myCommand.ExecuteReader()
DTResults.Load(myReader)
End Using
End Using
End Using
Of course you could easily test if this is the problem using the Sql Server Management Studio and call that stored procedure from you working PC and check what amount of time is required to complete. If the time is less than 30 seconds (the default timeout for the SqlCommand execution) then the problem is elsewhere and not in the Timeout value.

SqlDataReader vb.net keep connection open

I am using this code to get data:
Dim connetionString As String
Dim connection As SqlConnection
Dim sqlq As String
sqlq = "select top 1 * from table1 where smth"
Dim ds As New DataSet
connetionString = "Data Source=db;Initial Catalog=ic;User ID=id;Password=pass"
connection = New SqlConnection(connetionString)
Try
Using connection
Dim command As SqlCommand = New SqlCommand(sqlq, connection)
connection.Open()
Dim reader As SqlDataReader = command.ExecuteReader()
If reader.HasRows Then
Do While reader.Read()
x = reader.GetString(5)
Loop
End If
reader.Close()
End Using
Catch ex As Exception
End Try
This type of connection (with different sqlq [query]) I use a lot in diffenrent functions and every time I close the connection. I want to optimize it so it would take less time to get data. How do I do that?
It is best practise to always dispose/close a connection as soon as you're finished with it. Actually the connection-pool will not close the underlying physical connection but only flag this connection as reusable if it is closed. So if you don't close a connection it cannot be reused, hence the pool needs to create a new physical connection which is very expensive.
So only some minor improvements:
Const sql = "select top 1 * from table1 where smth"
Dim table As New DataTable()
Using con = New SqlConnection("Data Source=db;Init ....")
Using command = New SqlCommand(sql, con)
Using da= New SqlDataAdapter(command)
da.Fill(table)
End Using
End Using
End Using
You should use Using for any object implementing IDisposable. You should not use an empty Catch block.
Use connection pooling instead.
By default as long as the connection string is the same, connections will be taken from the same connection pool.
Shortly connection pool keeps not needed connections open, and return that connections on the next request, so you don't need to think about the time it take to open connection.
Keeping connections open for longer than you needed is bad idea, because it costs resources, and in general some servers can accept limited connections.

VB.NET - Multiple SQLDataReader's

I develop a lot in ASP.NET and I know that you can only open one SQLDataReader for each SQLConnection. However, this does not appear to be the case in VB.NET (form application) i.e. I have opened multiple SQLDataReaders for one connection object. Is this allowed in VB.NET?
If there is not an obvious answer to this then I will post some code.
Here is some code:
Public Function CheckActiveReviews()
Dim objCon As SqlConnection
Dim objCommand As SqlCommand, objCommand2 As SqlCommand
Dim objDR As SqlDataReader, objDR2 As SqlDataReader
Try
objCon = New SqlConnection("Data Source=TestDatabase;Initial Catalog=TestTable;User ID=TestUser;Password=TestPassword;MultipleActiveResultSets=True")
objCommand = New SqlCommand
objCommand.Connection = objCon
objCommand2 = New SqlCommand
objCommand2.Connection = objCon
objCon.Open()
objCommand.CommandText = "SELECT ID FROM Person WHERE PersonID > 1000"
objDR = objCommand.ExecuteReader()
Do While objDR.Read
objCommand2.CommandText = "SELECT * FROM Sport WHERE PersonID = #PersonID "
objCommand2.Parameters.AddWithValue("#PersonID", objDR("ID"))
objDR2 = objCommand2.ExecuteReader
Loop
Catch ex As Exception
End Try
End Function
You can use multiple data readers if you use MARS - Multiple Active Result Sets - but I wouldn't advise that unless you really need it.
Instead, I'd suggest creating a new SqlConnection object each time you need it - use it for as short a period as you can, then dispose of it (use a Using statement to do this for you). The connection pool will take care of the efficiency in terms of reusing "physical" network connections where possible. That way you don't need to worry about whether the SqlConnection is already open etc - you just always follow the same "create, open, use, dispose" pattern every time.