disposing SqlCommand and SqlConnection

G

Guest

I'd love to get some definitive advice about calling Dispose() on SqlCommand
and SqlConnection in .NET 2.0. There's a lot of confusing advice out there in
the net.

From what I read and see in Reflector, SQLCommand doesn't do anything
special with Dispose. Calling Dispose() on it doesn't do much harm and might
be good discipline since in some future version it might be important.

With respect to SqlConnection, it gets more complicated. Two issues:

1. I often use the pattern for ExecuteReader with the
CommandBehavior.CloseConnection parameter and then return the reader to a
calling routine. The calling routine iterates thru the reader and ultimately
closes the reader, thus closing the connection. There's no good opportunity
to Dispose the SqlConnection. If Disposing is important, then I don't see how
to use this pattern.

2. There are several posts that say that if a SqlConnection is Disposed,
then it won't be released to the ConnectionPool. If you want the connection
to be pooled, only call Close(). Is there any truth to this?

I'd appreciate any advice.
 
W

WenYuan Wang [MSFT]

Hello Mike

I think there must be thousands of articles about such issue (Dispose or
Close).

For SQLCommand, in my opnion, Dispose is recommended, but not necessary. In
general, we suggest put the SQLCommand object in using block
(such as:Using(SQLCommand scd=new SQLCommand()){....})
SQLCommand object will be disposed automatically when out of scope.

For SQLConnection, Dispose is necessary, otherwise the connection will not
put back into Connection pool. I assume you must have read many documents
about this behavior.

When calling : Sqlconnection.Dispose():
We are actually removing the connection object and put it back into SQL
Server Connection Pool.
But when calling : Sqlconnection.Close():
We reserve the connection object for later use. This means, we may open it
again for later.

For the case of using the pattern for ExecuteReader with the
CommandBehavior.Close, we could use using block. Such as:
using (System.Data.SqlClient.SqlConnection sc = new
System.Data.SqlClient.SqlConnection())
{
using (System.Data.SqlClient.SqlCommand scd = new
System.Data.SqlClient.SqlCommand("select...", sc))
{
System.Data.SqlClient.SqlDataReader
sdr=scd.ExecuteReader(System.Data.CommandBehavior.CloseConnection);
 
G

Guest

Are you saying that Dispose _does_ put the connection back into the pool? I
had read that Close puts it back in the pool, but Dispose removes it from the
pool.

About Dispose(), you said "We are actually removing the connection object
and put it back into SQL Server Connection Pool." This is a bit confusing;
I'm not sure what the "it" refers to. Can you elaborate?

The distinction you are making implies that if Dispose is used, at least
something remains in the connection pool, but something has to be
reconstructed when the item in the pool is reused. Is there extra overhead in
constructing that item?

I thought the whole idea of the connection pool was to keep connections
around so they can be reused.

about CloseConnection: You suggest nested using blocks. That might work if
you are consuming the reader in the same routine which creates the connection
and command, e.g.

using (SqlConnection conn = new SqlConnection...)
{
using (SqlCommand cmd = new SqlCommand...)
{
using (SqlDataReader rdr =
cmd.ExecuteReader(CommandBehavior.CloseConnection))
{
while (rdr.Read())
...do something
}
}
}

But two issues:

A) in this pattern, the CloseConnection is superfluous. The using for the
Connection will close the connection anyway. (And I've seen some articles
that claim that trying to close the connection twice - ie. one from the
Closeconnection and one from the connection using block - causes noticable
performance overhead.

B) I think this defeats the whole purpose of CloseConnection. As I
understand it, this allows one to have a helper routine that encapsulates all
the Data related "overhead". The helper returns the resulting reader to the
caller, something like

public SqlDataReader ExecuteReaderHelper(string sql)
{
//using (SqlConnection conn = new SqlConnection...)
SqlConnection conn = new SqlConnection...
{
using (SqlCommand cmd = new SqlCommand...)
{
return cmd.ExecuteReader(CommandBehavior.CloseConnection))
}
}
}

....calling code

using (SqlDataReader rdr = ExecuteReaderHelper(sql))
{
while (rdr.Read())
...do something
}

Now when the caller has finished with the Reader, it closes it, which in
turn closes the connection. But the connection is not Disposed.

If we instead use the commented out line, then this doesn't work, because
the connection closes before the caller has a chance to iterate thru the
reader.
 
W

WenYuan Wang [MSFT]

Hello Mike,
It seems my first reply has been truncated. I'm sorry about that.

For your last question:
2. There are several posts that say that if a SqlConnection is Disposed,
then it won't be released to the ConnectionPool. If you want the connection
to be pooled, only call Close(). Is there any truth to this?

Actually, there are two connection pools, one is in application and the
other is in SQL server.
Which I mean is the connection pool in SQL server rather than application
connection pool.
I think you are talking about application connection pool. If you call the
close method of connection, the connection will be pooled in application
pool. However, if you dispose the connection, it will be destroyed and
released. Because SQL server supports connection pool, thus the connection
will be pooled in SQL connection pool. This connection will be use for next
request.
Are you saying that Dispose _does_ put the connection back into the pool?
I had read that Close puts it back in the pool, but Dispose removes it from
the pool.

Yes, I'm talking the connection pool in the SQL server rather than
Application connection pool.
For application connection pool, the close method will put the connection
in to pool(application). However, in SQL Server, the connection is still
connected. Thus if there is another request for SQL Server, SQL server
should have to create another connection for the new request. Thus, if you
need not use this connection, we suggest you dispose it and the connection
will not be pooled in application connection pool. SQL server noticed that
connection has been close; therefore, the server could close it and pooled
it in SQL server connection pool for next request.
The distinction you are making implies that if Dispose is used, at least
something remains in the connection pool, but something has to be
reconstructed when the item in the pool is reused. Is there extra overhead
in constructing that item?

Because the connection is also pooled in SQL server, therefore, it doesn't
need to construct it again for another request. However, if there are 5
connections in SQL connection pool, you have created 5 connection in
current application and forget to dispose them. For next request(6th), SQL
server will necessary to create another connection for the new request.
There is extra overhead in constructing that item.

For your last two issues, I think I should perform more research.
I will update here as soon as I got any suggestion.

Have a great weekend.
Sincerely,
Wen Yuan
Microsoft Online Community Support
==================================================
This posting is provided "AS IS" with no warranties, and confers no rights.
 
W

WenYuan Wang [MSFT]

Hello Mike,
Sorry for delay, due to weekend.

For such issue, we may change the code organization.
As far as helper method goes, we should not create a new instance of the
Connection in the method. We should create and open just one connection for
the code to use. Connections can be expensive and have to be monitored.
So we create and open the connection once and pass that into helper method.
That way we can wrap the connection with a using statement to guarantee
the object will be disposed.

public SqlDataReader ExecuteReaderHelper(SqlConnection cn)
{
using (SqlCommand cmd = new SqlCommand...)
{
return cmd.ExecuteReader(CommandBehavior.CloseConnection))
}
}


...calling code

using(SqlConnection cn=new SqlConnection(...))
{
using (SqlDataReader rdr = ExecuteReaderHelper(cn))
{
while (rdr.Read())
...do something
}
}

Hope this helps.
Sincerely,
Wen Yuan
Microsoft Online Community Support
==================================================
This posting is provided "AS IS" with no warranties, and confers no rights.
 
W

WenYuan Wang [MSFT]

Dear Mike,

This is Wen Yuan again.
I just want to check if you still have anything unclear or anything we can
help with.
Please feel free to update here, we are glad to assist you.

Have a great day,
Sincerely,
Wen Yuan
Microsoft Online Community Support
==================================================
This posting is provided "AS IS" with no warranties, and confers no rights.
 
G

Guest

Sorry, this doesn't make any sense to me.

Why bother opening the connection with CommandBehavior.CloseConnection if
the connection object is wrapped in a using block? On exit from the using,
the connection will be disposed, which will close the connection. As
previously mentioned, it appears as if the motivation behind
CommandBehavior.CloseConnection is precisely so a helper method can create
the connection, but the caller can then use the reader and subsequently close
the connection.

I also don't understand your point about "We should create and open just one
connection for the code to use. Connections can be expensive and have to be
monitored." Your scheme is creating a connection for each call the same as
mine.

As to your previous message, all of this discussion about two connection
pools is brand new to me. I haven't seen any references to the existence of
two pools in any documentation or posts before. Can you clarify or point me
to more documentation?
 
W

WenYuan Wang [MSFT]

Dear Mike,
Thanks for your response.

After further research on this issue these days, I'm sorry I made a mistake
in my previous replies.
connection.dispose() is "equal" to connection.close() (just as you have
seen by Reflector).
We need to close the connection only once. (using either close() or
dispose())

There are truly two connection pools (one in SQL Server and another in
ADO.net Application). However, the connection pool in SQL Server is
transparent to .net application.
Connection.dispose() method couldn't release connect to SQL connection
pool.(I'm sorry I explained wrong in my pervious reply).
Both connection.close() and connection.dispose() method return the
connection into the application connection pool.

Please note the CAUTION part in the following article on MSDN website.

http://msdn2.microsoft.com/en-us/library/8xx3tyca(vs.71).aspx
[Connection Pooling for the .NET Framework Data Provider for SQL Server]

CAUTION It is recommended that you always close the Connection when you
are finished using it in order for the connection to be returned to the
pool. 1)*THIS CAN BE DONE USING EITHER THE CLOSE OR DISPOSE METHODS OF THE
CONNECTION OBJECT*. 2)*CONNECTIONS THAT ARE NOT EXPLICITLY CLOSED MIGHT NOT
BE ADDED OR RETURNED TO THE POOL*. For example, a connection that has gone
out of scope but that has not been explicitly closed will only be returned
to the connection pool if the maximum pool size has been reached and the
connection is still valid.

If we FORGET to call close/dispose method, (in turn, dispose() method calls
connection.close() method implicit), the connection will NOT be released to
application pool, even though, the connection has gone out of scope.

We could repro this issue by the following code.

//we created an application connection pool (min=2, max=4).
// we added four connections in one scope and add two
connections out of scope.
//we will receive a time out exception when open the 5th
connection (sc5).
string connectionstring = @"Data Source=.;Initial
Catalog=testDB;Integrated Security=True;Min Pool Size=2;Max Pool Size=4";
{
System.Data.SqlClient.SqlConnection sc1 = new
System.Data.SqlClient.SqlConnection(connectionstring);
System.Data.SqlClient.SqlConnection sc2 = new
System.Data.SqlClient.SqlConnection(connectionstring);
System.Data.SqlClient.SqlConnection sc3 = new
System.Data.SqlClient.SqlConnection(connectionstring);
System.Data.SqlClient.SqlConnection sc4 = new
System.Data.SqlClient.SqlConnection(connectionstring);

sc1.Open();
sc2.Open();
sc3.Open();
sc4.Open();
}
System.Data.SqlClient.SqlConnection sc5 = new
System.Data.SqlClient.SqlConnection(connectionstring);
System.Data.SqlClient.SqlConnection sc6 = new
System.Data.SqlClient.SqlConnection(connectionstring);
sc5.Open();// Error(Time out)
sc6.Open();

Therefore, MSDN document suggest us use "Using()" block to ensure the
connection will be closed timely.
"Using" block will call dispose () method at the end of scope. In turn,
Dispose() method will call close() method of connection object. Therefore,
the connection could be return into application pool timely.

However, if you have called connection.close() before, it is NOT necessary
to dispose the connection again. Close() and Dispose() do the same thing
for connection.

Again, for your initial issues:
1. I often use the pattern for ExecuteReader with the
CommandBehavior.CloseConnection parameter and then return the reader to a
calling routine. The calling routine iterates thru the reader and
ultimately
closes the reader, thus closing the connection. There's no good opportunity
to Dispose the SqlConnection. If Disposing is important, then I don't see
how
to use this pattern.
not to dispose the connection again. However, please make sure we have
closed the connection.

2. There are several posts that say that if a SqlConnection is Disposed,
then it won't be released to the ConnectionPool. If you want the connection
to be pooled, only call Close(). Is there any truth to this?
application connection pool.

3. I think this defeats the whole purpose of CloseConnection. As I
understand it, this allows one to have a helper routine that encapsulates
all the Data related "overhead". The helper returns the resulting reader to
the caller, something like
public SqlDataReader ExecuteReaderHelper(string sql)
{
//using (SqlConnection conn = new SqlConnection...)
SqlConnection conn = new SqlConnection...
{
using (SqlCommand cmd = new SqlCommand...)
{
return cmd.ExecuteReader(CommandBehavior.CloseConnection))
}
}
}

...calling code

using (SqlDataReader rdr = ExecuteReaderHelper(sql))
{
while (rdr.Read())
...do something
}
(CommandBehavior.CloseConnection option). It is not necessary to call
dispose method again.
The connection will be return to connection pool timely.

4. As to your previous message, all of this discussion about two connection
pools is brand new to me. I haven't seen any references to the existence of
two pools in any documentation or posts before. Can you clarify or point me
to more documentation?
Application Connection Pool (Not SQL Connection Pool) by Dispose method.
I'm sorry.

Thanks for your patience.
Please let me know if you have any more concern. It's my pleasure to work
with you.
Best regards,
Wen Yuan
Microsoft Online Community Support
=================================================
This posting is provided "AS IS" with no warranties, and confers no rights.
 
G

Guest

Thatnks for the long and detailed reply. I do appreciate your help.

The most important statement you made is that dispose() is the same as
close() for SqlConnection. You implied that this confirms what I had seen in
Reflector.

My comment was that I can see that they are the same for SqlCommand, but the
situation for SqlConnection was much more complicated. If you are indeed
saying that these are also equivalent for Connection, that's an important key
to the whole question. Are you quite sure this is the case?
 
W

WenYuan Wang [MSFT]

Hello Mike,
Thanks for your reply.

I think they are the "same" in ADO.net.

1) Dispose () closes the connection and put the connection back into
application connection pool (just as what close() method do).

In order to prove this, we can use the following SQL statement to check how
many connections between .net client and SQL server 2005,

SELECT program_name, count(*)
FROM Master..sysprocesses
WHERE ecid=0
GROUP BY program_name

string connectionstring = @"Data Source=.;Initial Catalog=testDB;Integrated
Security=True;Min Pool Size=2;Max Pool Size=4";
{
System.Data.SqlClient.SqlConnection sc1 = new
System.Data.SqlClient.SqlConnection(connectionstring);
System.Data.SqlClient.SqlConnection sc2 = new
System.Data.SqlClient.SqlConnection(connectionstring);
System.Data.SqlClient.SqlConnection sc3 = new
System.Data.SqlClient.SqlConnection(connectionstring);
System.Data.SqlClient.SqlConnection sc4 = new
System.Data.SqlClient.SqlConnection(connectionstring);
sc1.Open();//.Net SqlClient Data Provider =1 (Count)


sc2.Open();//.Net SqlClient Data Provider =2
sc3.Open();//.Net SqlClient Data Provider =3
sc4.Open();//.Net SqlClient Data Provider =4

*sc1.Dispose();//.Net SqlClient Data Provider =4
*sc2.Dispose();//.Net SqlClient Data Provider =4
*sc3.Dispose();//.Net SqlClient Data Provider =4
*sc4.Dispose();//.Net SqlClient Data Provider =4
}

After Dispose, the number of connections between .net client and SQlserver
doesn't reduce. Therefore, the displose method does NOT return the
connection to SQL Server. The connection is pooled in Application
connection pool.

2) However, the only difference is that, after using Dispose(), we should
not use the connection object anymore. The Dispose method releases
resources used by connection object rather than waiting for the GC to do
this.

string connectionstring = @"..";
{
System.Data.SqlClient.SqlConnection sc1 = new
System.Data.SqlClient.SqlConnection(connectionstring);
sc1.Open();
*sc1.Dispose();
sc1.Open(); //Runtime error.

System.Data.SqlClient.SqlConnection sc2 = new
System.Data.SqlClient.SqlConnection(connectionstring);
sc2.Open();
*sc2.Close();
sc2.Open(); //This line works fine.
}

Please let me know if you have any more concern on this. It's my pleasure
to assist you.
Best regards,
Wen Yuan
Microsoft Online Community Support
==================================================
This posting is provided "AS IS" with no warranties, and confers no rights.
 
W

WenYuan Wang [MSFT]

Hello Mike,

Again, I'm pretty sure they are the same. I have consulted with ADO.net
product team on this issue today.

From MSDN
http://msdn2.microsoft.com/en-us/library/system.data.sqlclient.sqlconnection
.close(VS.80).aspx

If the SqlConnection goes out of scope, it is not closed. Therefore, unless
you have placed your code inside of a using statement, you must explicitly
close the connection by calling Close or Dispose. *THEY ARE FUNCTIONALLY
EQUIVALENT*. If the connection pooling value Pooling is set to true or yes,
this also releases the physical connection.

Dispose/Close are the same thing. You just need to call one of them.

Please let me know if there is anything unclear, I will follow up. It's my
pleasure to work with you.
Have a great day,
Best regards,
Wen Yuan
Microsoft Online Community Support
==================================================
This posting is provided "AS IS" with no warranties, and confers no rights.
 
G

G.Doten

WenYuan said:
Hello Mike,

Again, I'm pretty sure they are the same. I have consulted with ADO.net
product team on this issue today.

From MSDN
http://msdn2.microsoft.com/en-us/library/system.data.sqlclient.sqlconnection
.close(VS.80).aspx

If the SqlConnection goes out of scope, it is not closed. Therefore, unless
you have placed your code inside of a using statement, you must explicitly
close the connection by calling Close or Dispose. *THEY ARE FUNCTIONALLY
EQUIVALENT*. If the connection pooling value Pooling is set to true or yes,
this also releases the physical connection.

Dispose/Close are the same thing. You just need to call one of them.

Please let me know if there is anything unclear, I will follow up. It's my
pleasure to work with you.
Have a great day,
Best regards,
Wen Yuan
Microsoft Online Community Support
==================================================
This posting is provided "AS IS" with no warranties, and confers no rights.

Just an FYI for this thread: you can also specify CommandBehavior.Close
(something like that) when you create a DataReader which means that when
the DataReader is closed then the underlying connection is already closed.

But always wrap these in using statements whenever possible was Wen says.
 
W

WenYuan Wang [MSFT]

The pleasure is all mine.

Have a great day,
Best regards,
Wen Yuan
Microsoft Online Community Support
==================================================
This posting is provided "AS IS" with no warranties, and confers no rights.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top