views:

793

answers:

9

When I'm creating temp tables I get an error message telling me that the temp table already exists. The temp table is unique to the session so it seems my connection isn't closing properly and I think it may have something to do with a return statement I have in my using statement.

I have the following code:

using (IDbConnection connection = dbConnectionHandler.CreateConnection())
{
   connection.Open();
   CreateATempTable();
   PopulateTempTable();
   DataSet ds = CallStoredProcThatUsesTempTable();
   return ds;
}

I use this sort of code in several places to create a temp table with the same name.

Unfortunately, I'm getting the following error: There is already an object named '#MyTempTable' in the database.

Now, I know that the temp table is unique to the session and so once the session is closed it should disappear.

There are three things that I believe might cause this...

  1. I need to call connection.Close()
  2. I need to place the return statement outside my using statement
  3. I need to drop the temp table I created prior to returning

Does anyone know which one it is? or if its something I haven't thought of?

+1  A: 

Unless a power cycle occurs or some other seriously bizarre corner case dispose WILL be called.

If you want proof wrap the object and put a breakpoint in.

Quibblesome
If the power cycles, it will definitely dispose the object ;-)
Chris Ballance
Aye, but dispose wont be called, so if you have a remote resource that requires a login/logout then you'll have to wait for the timeout instead, if your remote resource has a timeout that is.
Quibblesome
But you wouldn't connect back to the same session, so the #TempTable would be out of scope, and no conflict would arise...
Dems
Wait... i'm only talking about the fact that Dispose is guaranteed to be called except in the above cases. The whole "login/logout" scenario is just a potential issue in an imaginary remote setup where a power cycle means dispose isn't called and it leads to an issue.
Quibblesome
A: 

Without knowing more about the database connection library in use, I'd guess it's neither of the first two; using was introduced specifically to make cleaning up such resources easier when returning out of methods; it's directly analogous to an ordinary try...finally block in Java or similar.

In other words, the return will leave the block and the Dispose method will be called on the connection, which should, assuming a sane implementation of such, call the Close method as part of that process.

The key point here is "sane implementation".

Rob
A: 

A using block is translated into a try/catch/finally block under the hood. Yes it will dispose regardless of the return within the using block.

Chris Ballance
+3  A: 

I am pretty sure that connection.Dispose() (and thus connection.Close() as well) will be called.

You can verify that easily enough by doing 1) and 2) and checking that the problem still exists. The solution is probably 3) and the explanation would be Connection pooling.

Henk Holterman
+1  A: 

No, connection.Close will always be called because internally using puts it in a try/finally block.

You also may want to consider connection pooling. Try wrapping your code in a TransactionScope.

Andrew Peters
A: 

To answer your questions:

  1. The using statement will implicitly close the connection, when the connection's Dispose method is called.
  2. That should not be needed: http://aspadvice.com/blogs/name/archive/2008/05/22/Return-Within-a-C_2300_-Using-Statement.aspx
  3. Try it.
MartinHN
A: 

using statement will dispose the object if its class is IDisposable even there is a return statement within the using block.

It is the connection pooling that keeps your #temptable, you might want to drop that table manually.

codemeit
+6  A: 

I'm guessing here but check your database connection pooling settings. Try turning pooling off and see if it helps.

Usually, when you close/dispose connection on the .NET libraries level, real database server connection is not closed. It is just returned to connection pool inside data provider and will be reused when program asks for another connection with the same parameters and credentials. I don't think database session is reset in any way before being returned to the pool, except for open transactions and maybe some basic parameters. More expensive objects, like temporary tables, are left alone.

You can turn pooling off (very inefficient). Or you can check temporary table existence before trying to create it and delete its content if it exists. Or you can drop temporary table before closing connection.

Tomek Szpakowicz
For now, dropping the table before the connection is closed gets it to work. Not really happy with that method because I don't feel I should be manually managing that...but until I find a better way I'll move on to something else...
mezoid
I think such coupling create and drop together (get connection, create temp table, do the work, drop temp table, release connection) is a good design in your situation. Just be careful not to leave the table in case of some errors in the do-the-work part.
Tomek Szpakowicz
A: 

It's being caused by connection pooling. Wrap what you are doing in a transaction, and roll it back at the end. Or, drop the temp table after populating the ds.

Noel Kennedy