32

I usually use code like this:

using (var connection = new SqlConnection(ConfigurationManager.ConnectionStrings["MyConn"].ConnectionString))
{
   var command = connection.CreateCommand();
   command.CommandText = "...";
   connection.Open();
   command.ExecuteNonQuery();
}

Will my command automatically disposed? Or not and I have to wrap it into using block? Is it required to dispose SqlCommand?

abatishchev
  • 98,240
  • 88
  • 296
  • 433

6 Answers6

33

Just do this:

using(var connection = new SqlConnection(ConfigurationManager.ConnectionStrings["MyConn"].ConnectionString))
using(var command = connection.CreateCommand())
{
   command.CommandText = "...";
   connection.Open();
   command.ExecuteNonQuery();
}

Not calling dispose on the command won't do anything too bad. However, calling Dispose on it will suppress the call to the finalizer, making calling dispose a performance enhancement.

Pang
  • 9,564
  • 146
  • 81
  • 122
RichardOD
  • 28,883
  • 9
  • 61
  • 81
  • 19
    "Not calling dispose on the command won't do anything too bad." True, but don't get used to it; it's only true for `SqlCommand` s. On the other hand, not disposing a `SqlCeCommand`, for example, *will* cause your mobile device to run out of memory quite fast. (Just been there, done that...) – Heinzi Apr 15 '10 at 16:16
  • 6
    `Dispose` doesn't suppress finalization since the constructor does that. – Edward Brey Oct 16 '15 at 21:33
  • @EdwardBrey which constructor? – Serg Apr 01 '19 at 18:59
  • @Sergey The [`SQLConnection` constructor](https://github.com/dotnet/corefx/blob/d2db42612c462f64f6520106cce17fe973c27bb6/src/System.Data.SqlClient/src/System/Data/SqlClient/SqlConnection.cs#L91). – Edward Brey Apr 01 '19 at 22:28
  • 1
    @EdwardBrey it's done only in the private constructor `SqlConnection(SqlConnection connection)` which can be called only from the [`Clone()`](https://github.com/dotnet/corefx/blob/d2db42612c462f64f6520106cce17fe973c27bb6/src/System.Data.SqlClient/src/System/Data/SqlClient/SqlConnection.cs#L1573) method. But none of the two normal public constructors does call `GC.SuppressFinalize`, only the [`Close()`](https://github.com/dotnet/corefx/blob/d2db42612c462f64f6520106cce17fe973c27bb6/src/System.Data.SqlClient/src/System/Data/SqlClient/SqlConnection.cs#L684) method does. So I guess you're wrong. – Serg Apr 02 '19 at 20:29
  • 1
    @Sergey Sorry. I linked to the wrong constructor. It's the [SQLCommand constructor](https://github.com/dotnet/corefx/blob/master/src/System.Data.SqlClient/src/System/Data/SqlClient/SqlCommand.cs#L215) that matters, and it does always call `GC.SuppressFinalize`. – Edward Brey Apr 03 '19 at 16:08
  • @EdwardBrey right, and I should have been more careful, too. Ok, in this version it suppresses the finalizer in advance (which is quite unusual for the `IDisposable` pattern) but they can change it in future versions, so, we'd better follow the protocol either way, especially since `SqlCommand` has the [`Dispose`](https://github.com/dotnet/corefx/blob/master/src/System.Data.SqlClient/src/System/Data/SqlClient/SqlCommand.cs#L781) method that does some work. – Serg Apr 03 '19 at 17:47
  • Maybe `SqlCommand.Dispose` contains a [bug](https://github.com/dotnet/corefx/issues/36573). – Edward Brey Apr 03 '19 at 18:29
16

The safest policy is to always call Dispose() on an object if it implements IDisposable, either explicitly or via a using block. There may be cases where it is not required but calling it anyway should never cause problems (if the class is written correctly). Also, you never know when an implementation may change meaning that where the call was previously not required it is now definitely required.

In the example you've given, you can add an extra inner using block for the command, as well as maintaining the outer using block for the connection.

Gonzalo.-
  • 12,512
  • 5
  • 50
  • 82
Adam Ralph
  • 29,453
  • 4
  • 60
  • 67
  • 3
    Yes, the safest policy is to always dispose disposable objects - notably if you *created* it! It's not a good idea for example to write a method that accepts a stream, and dispose the stream inside that method. Another caveat is that you can't always dispose via the using statement with impunity. WCF proxies are the only practical example I know of. If something goes wrong at the remote end and you get an exception the channel closes and Dispose then throws a new exception, replacing the original exception, which can be a serious problem. – The Dag Aug 09 '12 at 12:21
6

Yes, you should, even if it the implementation is currently not doing much, you don't know how it is going to be changed in the future (newer framework versions for instance). In general, you should dispose all objects which implement IDisposable to be on the safe side.

However, if the operation is deferred and you don't control the full scope (for instance when working asynchroneously, or when returning an SqlDataReader or so), you can set the CommandBehavior to CloseConnection so that as soon as the reader is done, the connection is properly closed/disposed for you.

Lucero
  • 59,176
  • 9
  • 122
  • 152
6

In practice, you can skip Dispose. It doesn't free any resources. It doesn't even suppress finalization since the SQLCommand constructor does that.

In theory, Microsoft could change the implementation to hold an unmanaged resource, but I would hope they'd come out with an API that gets rid of the Component base class long before they'd do that.

Edward Brey
  • 40,302
  • 20
  • 199
  • 253
3

You can find out this kind of stuff using Reflector or dotPeek or https://referencesource.microsoft.com/.

I had a small dig (I would suggest that you dig yourself though to be fully sure of the rest of this though as I didn't try that hard) and it looks like when you kill a connection there is no disposal of any children associated with that connection. Furthermore it doesn't actually look like the disposal of a command actually does that much. It will set a field to null, detach itself from a container (this may prevent a managed memory leak) and raise an event (this might be important but I can't see who is listening to this event).

Either way it's good practice to use this stuff in a using block or to ensure you dispose of it using a dispose pattern in the object that holds the connection (if you intend to hold onto the command for a while).

Quibblesome
  • 25,225
  • 10
  • 61
  • 100
0

In my opinion, calling Dispose for both SqlConnection and SqlCommand is good practice, use below code

using(var connection = new SqlConnection(ConfigurationManager.ConnectionStrings["MyConn"].ConnectionString))
try{
    using(var command = connection.CreateCommand())
    {
       command.CommandText = "...";
       connection.Open();
       command.ExecuteNonQuery();
    }
}
catch(Exception ex){ //Log exception according to your own way
    throw;
}
finally{
    command.Dispose();
    connection.Close();
    connection.Dispose();
}
Tahir Alvi
  • 896
  • 2
  • 14
  • 44
  • 4
    You don't need any of this code if you have `using`: compilter will generate the try/catch/dispose() for you. – abatishchev Mar 01 '19 at 23:50
  • @abatishchev, yes you are right, but it is always a good practice to catch any exception and logged it properly. – Tahir Alvi Mar 14 '19 at 07:15
  • 1
    Not this sort of exception handling. If the excepting is throw from the constructor of SqlConnection(bad connection string or null value in config) both connection and command will be null. You'll literally get another null exception in the "finally" statement. The using statements will ensure dispose gets called EVEN if there's an exception. Literally NO need to handle disposing anywhere when using a "using" statement. – Looooooka Sep 20 '22 at 12:33