Wednesday, June 02, 2004
« Better version of the .NET 2.0 event/ser... | Main | CSLA workshop at VS Live Orlando »

Most people (including me) don’t regularly Dispose() their Command objects when doing data access with ADO.NET. The Connection and DataReader objects have Close() methods, and people are very much in the habit (or should be) of ensuring that either Close() or Dispose() or both are called on Connection and DataReader objects.

 

But Command objects do have a Dispose() method even though they don’t have a Close() method. Should they be disposed?

 

I posed this question to some of the guys on the ADO.NET team at Microsoft. After a few emails bounced around I got an answer: “Sometimes it is important”

 

It turns out that the reason Command objects have a Dispose method is because they inherit from Component, which implements IDisposable. The reason Command objects inherit from Component is so that they can be easily used in the IDE on designer surfaces.

 

However, it also turns out that some Command objects really do have non-managed resources that need to be disposed. Some don’t. How do you know which do and which don’t? You need to ask the dev that wrote the code.

 

It turns out that SqlCommand has no un-managed resources, which is why most of us have gotten away with this so far. However, OleDbCommand and OdbcCommand do have un-managed resources and must be disposed to be safe. I don’t know about OracleCommand – as that didn’t come up in the email discussions.

 

Of course that’s not a practical answer, so the short answer to this whole thing is that you should always Dispose() your Command objects just to be safe.

 

So, follow this basic pattern in VB.NET 2002/2003 (pseudo-code):

 

Dim cn As New Connection("…")

cn.Open()

Try

  Dim cm As Command = cn.CreateCommand()

  Try

    Dim dr As DataReader = cm.ExecuteReader()

    Try

      ' do data reading here

 

    Finally

      dr.Close() ' and/or Dispose() – though Close() and Dispose() both work

    End Try

 

  Finally

    cm.Dispose()

  End Try

 

Finally

  cn.Close() ' and/or Dispose() – though Close() and Dispose() both work

End Try

 


And in C# 1.0 and 2.0 (pseudo-code):

 

using(Connection cn = new Connection("…"))

{

  cn.Open()

  using(Command cm = cn.CreateCommand())

  {

    using(DataReader dr = cm.ExecuteReader())

    {

      // do data reading here

    }

  }

}

 

And in VB 8 (VB.NET 2005) (pseudo-code):

 

Using cn As New Connection("…")

  cn.Open()

  Using cm As Command = cn.CreateCommand()

    Using dr As DataReader = cm.ExecuteReader()

      ' do data reading here

    End Using

  End Using

End Using

 

 


Wednesday, June 02, 2004 10:57:04 AM (Central Standard Time, UTC-06:00)
Dispose()ing your Command is ESPECIALLY important when using the Oracle driver (MSFT's, not ODP.NET). We found that when using various parameters, they don't get cleaned up after closing the connection, eating up resources on the Oracle instance. The only way to free them is to Dispose() the Command which in turn nukes the Parameters. If you're seeing Oracle running out of resources and you're using Commands with Input-Output parameters, try Dispose().
Jason Sherron
Thursday, June 10, 2004 4:00:27 PM (Central Standard Time, UTC-06:00)
I've long known the recommended practice is to use "using" for c#, but haven't made the jump from the VB-equivalent of nested try-catch-finally blocks. I always get stumped on how transactions fit into a "using" block though. In your c# pseudo-code above would you wrap a try-catch-finally block around it to rollback or commit transactions, or would the block be inside the two using blocks... OR can you use another "using" block for the transaction object?
Friday, June 11, 2004 9:28:18 AM (Central Standard Time, UTC-06:00)
Interesting, I did not know this. Thanks for the tip.
Sunday, June 13, 2004 10:41:28 PM (Central Standard Time, UTC-06:00)
You can't do transactions with just a using block - you need a try..catch block to do ADO.NET transactions. You can still rely on using to dispose the objects, but you need the try..catch to handle any exceptions and provide the appropriate rollback call.
Thursday, June 16, 2005 1:16:54 AM (Central Standard Time, UTC-06:00)
I just noticed the nested using{} statements. In C#, you can actually 'stack' usings like this:

using(Command cm = cn.CreateCommand())
using(DataReader dr = cm.ExecuteReader())
{

// do data reading here

}
Josh Twist
Wednesday, February 08, 2006 8:22:53 PM (Central Standard Time, UTC-06:00)
Dear Sirs,

I am working with CSLA version 1.3.6.0 and I need to execute a Store Procedure in Oracle that gives a cursor as a return.

Please help me with the procedure.

Thank you very much in advance.

Best regards,

Renato Penailillo
Renato Chile
Comments are closed.