1

I created a connection and an SqlReader but forgot to close both of them:

SqlConnection conn = new SqlConnection("connection info");
conn.Open();

string sql = "SQL command HERE";
SqlCommand cmd = new SqlCommand(sql, conn);
SqlDataReader reader = cmd.ExecuteReader();

Now when try to run the code again it always gives me this error:

System.InvalidOperationException: There is already an open DataReader associated with this Command which must be closed first.

This link told me how to properly open and close a connection but didn't explain anything on how to close one still running.

I tried shuting down the pc, I tried looking into the database's options on SQL server (found none useful)... I changed the code to do just the close of both the connection and the reader (it compiled and runned but the problem remained after changing back the code).

How can I close this "ghost" connection? Is there any way (brute force) to close all running connections?


[EDIT:] I couldn't really solve the problem. The workaround was to add MultipleActiveResultSets=true to the connection string

dialex
  • 2,706
  • 8
  • 44
  • 74
  • For future reference you should utilize the using() statement, as many have written. But, to get around your blocking issue try restarting the MSSQLSERVER instance if it's not in a production environment. – Localghost Apr 17 '12 at 19:50

6 Answers6

4

I don't think you can access the ghost object, for future, just use using construct where it's possible:

using(SqlConnection conn = new SqlConnection("connection info"))
{
   conn.Open();

   string sql = "SQL command HERE";
   SqlCommand cmd = new SqlCommand(sql, con);
   SqlDataReader reader = cmd.ExecuteReader();
....
}
Tigran
  • 61,654
  • 8
  • 86
  • 123
  • Again, I can't create a new connection the "right way" until I close the previous one. – dialex Apr 17 '12 at 19:32
  • if the `conn` is a global variable you can have a look on [ConnectionState](http://msdn.microsoft.com/en-us/library/system.data.sqlclient.sqlconnection.state.aspx) property to understand if the connection still open, so close it. – Tigran Apr 17 '12 at 19:34
  • @DiAlex - How exactly do you have an open connection when recompiling the application and redeploying it? – Oded Apr 17 '12 at 19:34
3

Wrap the creation in a using statement - this will always ensure the connection gets closed:

using(SqlConnection conn = new SqlConnection("connection info"))
{
   // your code
}
Oded
  • 489,969
  • 99
  • 883
  • 1,009
  • Yes I found that on the link I added to my OP. But my problem is that only works on future callings, it doesn't close my running connections. – dialex Apr 17 '12 at 19:32
  • 1
    @DiAlex - I don't quite understand what you mean by that. As soon as the application exists, the connection will close. The error you are seeing is due to the fact that you have not closed the connection before reusing it. – Oded Apr 17 '12 at 19:33
  • Ok that's nice. But every time I run the app a new connection is created, so the "reusing problem" shouldn't exist because I'm using a new one, right? Btw what should be inside the using statement, the connection or the SqlDataReader? Thx – dialex Apr 17 '12 at 20:59
  • 1
    @DiAlex - One `using` for each of those. – Oded Apr 17 '12 at 21:00
1

All of these answers tell you how to avoid the problem, but they don't explain what the problem is.

A SqlDataReader provides forward-only data access, which means that once you have used it and are done, you must close create a new one. See this blog for a detailed explanation. Basically, if you don't close the DataReader, then underthehood it will remain open dedicated to that connection and command.

As others have stated, its best to ensure you close all your resources.

using (SqlConnection connection = new SqlConnection("...")) {
    connection.Open();

    string sql = "SQL command HERE";

    using (SqlCommand cmd = new SqlCommand(sql, con))
    using (SqlDataReader reader = cmd.ExecuteReader()) {
            // do your stuff
    }
}
David Anderson
  • 13,558
  • 5
  • 50
  • 76
  • +1 for mentioning multiple using statements. Thx for the link, although I mentioned it on my OP :P – dialex Apr 17 '12 at 21:03
  • Ah didn't see it. On this monitor the link in your post is virtually identical to normal text. ;) Anyways I hope this helped you. The main reason you have the problem is that in the ADO.NET framework (part of .NET and what DataReader is a part of), and because you have a global variable (from what it sounds from other comments/answers/your replies), it kept a reference to a resource which is why you couldn't re-use it. – David Anderson Apr 17 '12 at 21:17
  • Btw I used your code and checked the "Activity Monitor", as mentioned by David Stratton, and the connection still isn't being closed at the end of execution. When I call sequentially two methods that use the same connection I get the same error, while when I call two times the same method all goes well. – dialex Apr 17 '12 at 21:42
  • Because you should not be using the same connection without first calling Close(), which does not gauruntee the connection will close on the server. If the server does not close the connection, then you are referencing the same connection that was not closed by calling Close(). This is why you should generally use a whole new connection. – David Anderson Apr 17 '12 at 21:48
  • What do you mean by a whole new connection? I'm using the `new` keyword on every method and I can't change the `SqlConnection`'s construtor parameter. Even explicitly calling `.Close()` the connection is still there, somehow. Shouldn't the `using` take care of disposing the connection? – dialex Apr 17 '12 at 21:56
  • Can you hit me up on Skype? (userid is `dcomproductions`) – David Anderson Apr 17 '12 at 22:08
1

Looking at all the answers, they seem to tell you how to avoid the problem.

If I'm not mistaken, what you mean is that a connection exists on both the client (your PC) and the server (The sql server) because you forgot to close it, and you're worried about it hanging out there forever.

Think of your connection to the server as a phone conversation. I could hang up on you, but it takes a few seconds for your phone to realize the connection is lost. You may sit there wondering if I've hung up, or just stopped talking. You really don't know. This is what happens on the server when a connection isn't closed properly. (On older landlines, you could leave the phone off the hook and tied up the line indefinitely.)

By closing the connection in code, you are effectively telling the server to close their end of the connection before closing your own. if you FAIL to close the conneciton, it will be closed on your end when the program exits or if you reboot, but the server may sit there with an open connection. (Think of someone sitting there wondering "Did he just hang up on me?")

If I'm not mistaken, what you want to get to is closing it at the SQL server end. (Getting them to "hang up".)

After rebooting, it is absolutely closed on your end. It should clear on its own at the server.

However, if you want to do it yourself, you can clear it at the server in code end using this info: How do you kill all current connections to a SQL Server 2005 database?

A far easier approach would be to just do it in SQL Server Management Studio as described here: http://www.mikebevers.be/blog/2009/07/kill-open-sql-processes-connections/

Community
  • 1
  • 1
David
  • 72,686
  • 18
  • 132
  • 173
  • That was exactly my problem and exactly what I needed to solve my problem! Thank you so much! For people using SQL server 2008 I recommend check [link](http://social.msdn.microsoft.com/Forums/en-US/sqldatabaseengine/thread/5cb020b5-44fb-465c-9efb-b789763f947e/) to find "Activity Monitor" option (they changed it's place). – dialex Apr 17 '12 at 21:37
0

Truth be told even when you "close" or "dispose" of a connection it does not really go away unless you explicitly disable Pooling in your connection string. You can however do this

http://msdn.microsoft.com/en-us/library/system.data.sqlclient.sqlconnection.clearpool.aspx

Matthew Sanford
  • 1,069
  • 1
  • 13
  • 21
0

I know this is an old post, and this may help no one. But I saw a opportunity to post what I saw wrong with this question.

First, you are creating a SqlConnection named conn but in your SqlCommand named cmd you are calling con as your connection. This is a problem:

SqlConnection conn = new SqlConnection("connection info");
conn.Open();

string sql = "SQL command HERE";
SqlCommand cmd = new SqlCommand(sql, con);
SqlDataReader reader = cmd.ExecuteReader();

This might be why it's giving you the error:

System.InvalidOperationException: There is already an open DataReader associated with this Command which must be closed first.

Second, to close a conn after you are done you use:

conn.Close();

Third, to close a SqlDataReader you use:

reader.Close();

But you just assigned the SqlDataReader to reader. You never actually opened the SqlDataReader. To open it use:

reader.Read();

Or:

while (reader.Read())
{
    // Code
}

Now a proper way to initilaize a connection and a SqlDataReader while opening and close them:

using (SqlConnection conn = new SqlConnection(sqlConnectionString))
{
    conn.Open();

    using (SqlCommand cmd = new SqlCommand())
    {
        cmd.Connection = conn;
        cmd.CommandText = "SELECT * FROM TableName;";

        SqlDataReader reader = cmd.ExecuteReader();

        reader.Read();

        if (reader.HasRows)
        {
            strCol1 = reader.GetValue(0).ToString();
        }

        reader.Close();
  }

  conn.Close();
}
ryantpayton
  • 385
  • 4
  • 18