13

I want to close the existing connections to an SQL Server so that I can do a restore on that database. I am using the entity framework. I tried executing

alter database YourDb 
set single_user with rollback immediate

but then I get an exception saying that

Connection was not closed

I can not figure out why the connections are not allowed to close?

This image shows the full exception

enter image description here

this is the method,

 public void dbQueueryExctr(string queuery)
        {
            SqlCommand cmd = new SqlCommand();
            SqlDataReader reader;


            using (SqlConnection connectionx = new SqlConnection(CONNECTIONSTRING))
            {

                connectionx.Open();
                //connectionx.Open(); // Removed
                cmd.CommandText = queuery;
                cmd.CommandType = CommandType.Text;
                cmd.Connection = connectionx;

                reader = cmd.ExecuteReader();
                connectionx.Close();


            }

Edit: I removed the first .Open(). Now I have only Open()

Sanke
  • 676
  • 2
  • 13
  • 30
  • are you connect to the database :-), i expect you would need to connect to the master database of the sql server instance where the database lives to run and alter database command. also see http://stackoverflow.com/questions/7197574/script-to-kill-all-connections-to-a-database-more-than-restricted-user-rollback – ozhug May 07 '15 at 05:29
  • why are you calling `.Open()` twice? – default May 07 '15 at 09:31
  • If you are using Entity Framework, why are you using `SqlConnection`? – default May 07 '15 at 09:34
  • .Open() twice is a mistake and I tried using it once and that changed nothing. – Sanke May 07 '15 at 09:52
  • 1
    Now that open is only called once you should be getting a different error. I'd take all the open's away and see what error you get. Regardless, your error you are posting with this question is not a direct problem with the closing the connection, it's a problem executing a query. If you put `SELECT * FROM TABLE_NAME` (where TABLE_NAME is a table in your database) you would get the same problem. Start simple and make it work, then try to add the complexity. – VulgarBinary May 07 '15 at 15:56
  • Are you still getting the same error message now that you only have one open? – Scott Chamberlain May 08 '15 at 20:29
  • Well there error was with closing the connection which is already opened. I think I have have no error with the .Open() cause the error is not changed. I am getting the same error as the screen shot. – Sanke May 09 '15 at 03:15
  • 1
    Could you maybe revert the Edit in your code snippet? Since people (like me) will look for a problem similar to theirs, this brings confusion. If I had seen right away you used to have 2 Open() statements, I could've skipped this question. You don't have to remove the mistake to show all the fix, the answer shows the fix. – Glubus Oct 17 '17 at 13:51

8 Answers8

15

It does seem that Entity Framework keeps a connection to the database. You can see it be executing sp_who2 in SQL Server Management Studio where Entity Framework is listed as EntityFrameworkMUE under ProgramName.

You don't have to use "raw" sql statements to disconnect the active connections though, it can be solved this way as well:

Server server = new Server(".\\SQLEXPRESS");
Database database = new Database(server, dbName);
database.Refresh();
server.KillAllProcesses(dbName);
database.DatabaseOptions.UserAccess = DatabaseUserAccess.Single;
database.Alter(TerminationClause.RollbackTransactionsImmediately);

//restore.SqlRestore(server);
default
  • 11,485
  • 9
  • 66
  • 102
  • This is another option to the SQL statements, I didn't know the syntax off the top of my head when I posted my answer. Thanks for posting this, it's a great additional option the OP could attempt. – VulgarBinary May 07 '15 at 15:59
  • 3
    If someone is looking for the namespace for Server: Microsoft.SqlServer.Management.Smo – kkCosmo Aug 02 '17 at 07:49
8

You get that error when you are call Open() on a connection twice. You should make all SqlConnection objects you create inside using blocks and only open them once.

If you are reusing connections "to make it faster" .NET already does that by default for you via Connection Pooling but you must dispose of the connection object to make it work.

Scott Chamberlain
  • 124,994
  • 33
  • 282
  • 431
  • Please explain me more. I tried by clearing the Connection pool. But it did not helped me. – Sanke May 07 '15 at 14:03
  • 2
    You don't clear the connection pool, your error is from the two Open() calls you had. Now that you got rid of the second Open() you are likely getting a different error. You should roll back your change and ask a new question with the new error you are getting (If you are getting the same error you have another spot in your program where you call Open twice, check the stack trace.) – Scott Chamberlain May 07 '15 at 14:25
4

You need to dispose the reader, the command and the connection. Your reader is not disposed. This code snippet will guarantee that the connection is closed even if there are exceptions thrown during the read process.

using (var conn = new SqlConnection("..."))
{
    conn.Open();
    using (var cmd = conn.CreateCommand())
    {
        cmd.CommandText = "Command text.....";
        using (var reader = cmd.ExecuteReader())
        {
           ....
        }
    }
}
Radin Gospodinov
  • 2,313
  • 13
  • 14
  • sorry I think this is not what I was looking for. – Sanke May 07 '15 at 14:03
  • This doesn't even go into comprehending what the OP is asking. Yes, you should do this but when you want to restore a database or make changes to it that requires it being offline disposing your connections does not solve the problem. This is *not* an answer to this question. – VulgarBinary May 11 '15 at 20:03
3

Your first problem (now that you have posted your code) is you call open twice:

    public void dbQueueryExctr(string queuery)
    {
        SqlCommand cmd = new SqlCommand();
        SqlDataReader reader;


        using (SqlConnection connectionx = new SqlConnection(CONNECTIONSTRING))
        {

            //YOU CALL OPEN HERE
            //DELETE THIS ONE!!!
            connectionx.Open();
            cmd.CommandText = queuery;
            cmd.CommandType = CommandType.Text;
            cmd.Connection = connectionx;

            //AND OPEN HERE
            connectionx.Open();

            reader = cmd.ExecuteReader();
            //You do not need connectionx.Close() here
            //You have it within a using which will dispose the connection
            //upon exiting the using scope.
            connectionx.Close();


        }

Next your problem will require you to reset the database to force close all connections. You will have to use a separate connection string to connect to MASTER not the database you are trying to close all connections to.

    alter database <data base>
           set offline with rollback immediate 

    alter database <data base>
           set online with rollback immediate

Once you have executed the above SQL from MASTER against the database needing reset you should be good to do whatever you need to do. Remember, connect to master!! If you connect to the database you are trying to reset you end up closing all connections, including yourself, which will not work!

Change your Catalog to master.

Example Connection String (from MSDN):

"Persist Security Info=False;Integrated Security=true;Initial Catalog=Master;server=(local)"

Also ensure the SQL User you are using has full permissions to master. You do this by opening management studio and looking at the users collection under master.

VulgarBinary
  • 3,520
  • 4
  • 20
  • 54
  • More detail would be great... If you open SQL Mgmt Studio and run that exact statement, does it not close all connections? – VulgarBinary May 07 '15 at 12:52
  • Saw you posted your code. conn.Open() then Conn.Open() is why you are blowing up. Fix that use my query, it'll work. – VulgarBinary May 07 '15 at 13:04
  • well in SQL Mgmt Studio it closes all the connections. but when I execute it with c# it do not as expected. – Sanke May 07 '15 at 13:51
  • 1
    Are you connecting to master? You would change your catalog to Master and you have to ensure the database user you are using has permissions to connect to master. If these 2 things are resolved correctly, it will work I verified this morning. – VulgarBinary May 07 '15 at 14:46
2

The error is pretty clear...using Linq that way, you can't close the connection you are currently on. I haven't tried this but I think the following would work...try creating a stored procedure in your database and run it in your C# code using either a TableAdapter or SqlCommand(you can still use Linq too). Your code won't know you are about to run a stored procedure that is about to kill it's connection so it should work.

CREATE PROCEDURE [dbo].[sp_KillSpidsByDBName] 
@dbname sysname = ''
AS
BEGIN

-- check the input database name
IF DATALENGTH(@dbname) = 0 OR LOWER(@dbname) = 'master' OR LOWER(@dbname) = 'msdb'
RETURN

DECLARE @sql VARCHAR(30) 
DECLARE @rowCtr INT
DECLARE @killStmts TABLE (stmt VARCHAR(30))

-- find all the SPIDs for the requested db, and create KILL statements 
--   for each of them in the @killStmts table variable
INSERT INTO @killStmts SELECT 'KILL ' + CONVERT (VARCHAR(25), spid)
FROM master..sysprocesses pr
INNER JOIN master..sysdatabases db
ON pr.dbid = db.dbid
WHERE db.name = @dbname

-- iterate through all the rows in @killStmts, executing each statement
SELECT @rowCtr = COUNT(1) FROM @killStmts
WHILE (@rowCtr > 0)
    BEGIN
        SELECT TOP(1) @sql = stmt FROM @killStmts
        EXEC (@sql)
        DELETE @killStmts WHERE stmt = @sql
        SELECT @rowCtr = COUNT(1) FROM @killStmts
    END

END

GO

Now you can run this stored procedure from code and it will kill open connections even your own. Enjoy!

waltmagic
  • 631
  • 2
  • 9
  • 22
2

It is good practice to check to see if the connection is open before attempting to open it. Try adding a check before trying to open your connection, something like this:

using (SqlConnection connectionx = new SqlConnection(CONNECTIONSTRING))
{

    if(connectionx.State != ConnectionState.Open
        connectionx.Open();
    cmd.CommandText = queuery;
    cmd.CommandType = CommandType.Text;
    cmd.Connection = connectionx;

    reader = cmd.ExecuteReader();

    connectionx.Close();


}

This will help prevent the issue you described.

Tom Miller
  • 536
  • 1
  • 4
  • 14
  • 1
    This doesn't even go into comprehending what the OP is asking. Yes, you should do this but when you want to restore a database or make changes to it that requires it being offline disposing your connections does not solve the problem. This is *not* an answer to this question. – VulgarBinary May 11 '15 at 20:04
1

You can use SqlConnection.ClearAllPools and SqlConnection.ClearPool to close all or one connection in from .NET.

ClearPool clears the connection pool that is associated with the connection. If additional connections associated with connection are in use at the time of the call, they are marked appropriately and are discarded (instead of being returned to the pool) when Close is called on them.

ClearAllPools resets (or empties) the connection pool. If there are connections in use at the time of the call, they are marked appropriately and will be discarded (instead of being returned to the pool) when Close is called on them.

for examples:

using(var comm = new SqlConnection())
  using(var comExecuteInsert = new SqlCommand())
  {
    comExecuteInsert.Connection = comm;
    comExecuteInsert.CommandType = CommandType.StoredProcedure;
    comExecuteInsert.CommandText = strProcedureName;
    comExecuteInsert.ExecuteScalar();
    comExecuteInsert.Parameters.Clear();
    comm.Close();
  }    

SqlConnection.ClearAllPools();
Behzad
  • 3,502
  • 4
  • 36
  • 63
  • So now use try/final blocks. and set try by connection codes such as open, execute, add params, and etc. And in finally block set close code to sure that connection closed already! – Behzad May 07 '15 at 09:19
0

Once exam this way, this is my Data access layer samples:

    public T ExecuteScalar<T>(SqlCommand cmd, params SqlParameter[] Params)
    {
        try
        {
            if (Transaction != null && Transaction != default(SqlTransaction))
                cmd.Transaction = Transaction;
            else
                cmd.Connection = SqlConn;

            if (Params != null && Params.Length > 0)
            {
                foreach (var param in Params)
                    cmd.Parameters.Add(param);
            }

            Open();

            var retVal = cmd.ExecuteScalar();

            if (retVal is T)
                return (T)retVal;
            else if (retVal == DBNull.Value)
                return default(T);
            else
                throw new Exception("Object returned was of the wrong type.");

        }
        finally
        {
            Close();
        }

    }
Behzad
  • 3,502
  • 4
  • 36
  • 63