19

SqlConnection, SqlCommand and SqlDataReader all implement the IDisposable interface. I read about a best practice to always wrap IDisposables into a using block.

So, my common scenario for querying data would look something like this (in greater context of course a mapping tool like linq2sql would be suitable, but lets just assume we want to use this approach here):

using (SqlConnection cn = new SqlConnection("myConnectionstring"))
{
    using (SqlCommand cm = new SqlCommand("myQuery", cn))
    {
        // maybe add sql parameters
        using (SqlDataReader reader = cm.ExecuteReader())
        {
             // read values from reader object
             return myReadValues;
        }
    }
}

Is this the correct way or could that be considered overkill? I am a little unsure about this level of nesting using blocks, but of course i want to do it the correct way. Thanks!

marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459
Dennis
  • 14,210
  • 2
  • 34
  • 54

7 Answers7

16

This is 100% the correct way. If a class leverages IDisposable it should be wrapped in a using statement to ensure that the Dispose() method is called. Further, communicating with an outside technology -unmanaged at that -like SQL Server shouldn't be taken lightly. The SqlCommand object implements IDisposable for a very good reason. The code below is the Dispose() method for the SqlCommand object:

protected override void Dispose(bool disposing)
{
    if (disposing)
    {
        this._cachedMetaData = null;
    }
    base.Dispose(disposing);
}

and as you can see, it's releasing a reference to the _cachedMetaData object so that it too can get cleaned up.

Mike Perrenoud
  • 66,820
  • 29
  • 157
  • 232
  • thanks for your answer, especially for detail about `SqlCommands`'s dispose - exactly the information i was looking for! – Dennis Jun 07 '13 at 14:06
  • @Chips_100, I'm glad I could be of assistance! – Mike Perrenoud Jun 07 '13 at 14:06
  • Just an FYI, "using" is syntactic sugar for a try --> finally block where the finally calls Dispose. Don't do it that way though - use the using keyword. :) – Haney Jun 07 '13 at 14:09
  • "it's releasing a reference to the `_cachedMetaData` object" - but in the OP's example, the _`cachedMetaData` object would become eligible for GC as soon as its containing `SqlCommand` goes out of scope, which is potentially sooner without the `using` statement than with it. NB I'm not arguing against calling Dispose: it's probably better not to rely on knowledge of the internals of `SqlCommand` and just follow the pattern blindly. – Joe Jun 07 '13 at 14:24
5

You can use the following way of typography to get the code closer to the left:

using (SqlConnection cn = new SqlConnection("myConnectionstring"))
using (SqlCommand cm = new SqlCommand("myQuery", cn))
using (SqlDataReader reader = cm.ExecuteReader())
{
     // read values from reader object
     return myReadValues;
}

As other already pointed out, using three nested using blocks is correct though.

Matthias Meid
  • 12,455
  • 7
  • 45
  • 79
  • If later on you go auto-identing the rest of your code (i.e.: Ctrl + K + D in Visual Studio), you lose that. – Geeky Guy Jun 07 '13 at 14:17
  • thanks, i didn't know of 'stacking' `using` declarations before. It's a nice thing to have, alghough i could for example not use that, if i need to add parameters to the SqlCommand. Thanks again for the info! – Dennis Jun 07 '13 at 14:19
  • 1
    @Renan Actually I don't lose it in VS2012. If I remember correctly, VS2010 did support this "using stack" too... – Matthias Meid Jun 07 '13 at 14:23
  • 4
    I don't think this code works, since the connection is never opened. Stacking it like this looks good, but it's just not viable since there's always stuff that needs to be done (cn.Open(), cm.Parameters.AddWithValue() etc) – Tobberoth Jul 17 '14 at 09:43
4

That is the correct way, if you will be done with the reader. Sometimes, you need the reader to remain open (maybe your method returns it), so it disposing the reader right away would not work. In those cases, there is an overload of the ExecuteReader that can help you:

var cn = new SqlConnection("myConnectionstring");
var cm = new SqlCommand("myQuery", cn);
var reader = cm.ExecuteReader(CommandBehavior.CloseConnection);
return reader;

This will keep the connection and the reader open. Once the reader is closed/disposed, it will also close (and dispose) the connection as well.

using(var reader = GetReader()) //which includes the code above
{
   ...
} // reader is disposed, and so is the connection.
Eren Ersönmez
  • 38,383
  • 7
  • 71
  • 92
  • Your `GetReader` example is flawed, as it doesn't dispose the connection if `new SqlCommand` or `ExecuteReader` throws. See the following answer for a more complete implementation: http://stackoverflow.com/a/744307/13087 – Joe Jun 07 '13 at 14:26
  • @Joe Good point, this is not a complete implementation (thanks for the link). The main thing I wanted to point out was the usage of `CommandBehavior.CloseConnection` when the reader needs to remain open. – Eren Ersönmez Jun 07 '13 at 15:15
2

This is not overkill. A using block is good practice because it ensures that the Dispose() method of the object will be called, even if an exception is thrown.

There is a name for this kind of thing, though. It's called code sugar. So:

using (foo bar = new foo()) { //...snip }

Is short hand code for:

foo bar = null;
Exception error = null;
try {
    bar = new foo();
    // ...snip
}
catch (Exception ex) {
    error = ex;
}
finally {
    if (bar != null) bar.Dispose();
    if (error != null) throw error;
}

Either form is equal to the other, they're just different ways to write the same thing. In other words, same difference between for and while: they do basically the same thing but are used in different ways.

using is preferred because it makes the code shorter and more readable, and automates the disposal for you. As to whether you should use it, though, don't listen to people who say you should always do something. It's good practice, granted, but knowing when to use, why to use and the benefits and consequences of using, or not using something is worth way more than doing something because people say you should.

Eren's answer has an example of a case where you wouldn't want to have a using block for the reader.

Geeky Guy
  • 9,229
  • 4
  • 42
  • 62
1

Yep that's correct. You can miss the braces out in nested using as they are one statement, but I don't feel that adds to readability.

Tony Hopkinson
  • 20,172
  • 3
  • 31
  • 39
-1

I don't see any point in disposing the SqlCommand. The SqlConnection and SqlDataReader should be disposed of though.

The SqlConnection because it won't close by itself when it goes out of scope.

The SqlDataReader can keep the SqlConnection busy until the reader is closed.

Not even MSDN examples dispose of the SqlCommand.

SamiHuutoniemi
  • 1,576
  • 2
  • 16
  • 35
  • Huh? It implements Idisposable, so it's going to get disposed of. Why would you leave it floating about, until (if) the GC kicks in. – Tony Hopkinson Jun 07 '13 at 14:05
  • It is widely accepted as a best practice to dispose of any class instance that implements `IDisposable`. The question isn't Why dispose of the `SqlCommand` but rather Why Not? – Evan L Jun 07 '13 at 14:07
  • I'm just pointing out that it is really not more important than getting anything else non-crucial disposed of. @TonyHopkinson, do you run the GC after every object you create goes out of scope? No? Because there is no point. Dispose also uses clock cycles. You should either argue against Garbage Collection in general, or not at all. – SamiHuutoniemi Jun 07 '13 at 14:14
  • There are classes such as SqlCommand, DataTable that implement IDisposable, but all they do is set a private reference to null, which has no effect if the containing instance is going out of scope anyway. I'd normally dispose SqlCommand, but strictly speaking this answer is correct, omitting the dispose will have no adverse effect. – Joe Jun 07 '13 at 14:16
  • 1
    Agree with Evan Lewis, and no I don't run GC, except in edge case scenarios. It's far more important to remember to Dispose, than to remember a couple of cases where you could get away with not doing it. Not to mention the inherent scoping it gives you.. – Tony Hopkinson Jun 07 '13 at 14:37
-2

I'm not an expert but i know that the using is translated into a try/finally block maybe you can wrap the SqlConnection, SqlCommand and SqlDataReader into a unique try/finally

try {
     // code here with SqlConnection, SqlCommand and SqlDataReader
}
finally
{
  // Dispose call on SqlConnection, SqlCommand and SqlDataReader
 }
Davide Lettieri
  • 326
  • 2
  • 13
  • Wasn't me who marked you down, but don't try this. It's not equivalent, and in the event of an exception will leak like a sieve and possibly raise even more exceptions an should raise a pile of warnings from the compiler. – Tony Hopkinson Jun 07 '13 at 14:03
  • @TonyHopkinson I answered just to have a feedback. Can you explain further why it's not equivalent? thank you very much! – Davide Lettieri Jun 07 '13 at 14:07
  • 1
    If sql connection connect raises an exception. Finally executes and then you get a null reference exception on the sqlcommand. To get round that you have to test for nil. – Tony Hopkinson Jun 07 '13 at 14:09