2009-10-12 15 views
5

dado el método:¿Por qué no está dispuesto/cerrado SqlConnection?

internal static DataSet SelectDataSet(String commandText, DataBaseEnum dataBase) 
{ 
    var dataset = new DataSet(); 

    SqlConnection sqlc = dataBase == DataBaseEnum.ZipCodeDb 
          ? new SqlConnection(ConfigurationManager.AppSettings["ZipcodeDB"]) 
          : new SqlConnection(ConfigurationManager.AppSettings["WeatherDB"]); 
    SqlCommand sqlcmd = sqlc.CreateCommand(); 
    sqlcmd.CommandText = commandText; 
    var adapter = new SqlDataAdapter(sqlcmd.CommandText, sqlc); 
    adapter.Fill(dataset); 


    return dataset; 
} 

Por qué se SQLC (SqlConnection) no se eliminan/cierre después de que el método de llamada fuera de ámbito o SQLC no tiene más referencias?

EDIT 1: Incluso envolviéndolo en el uso, todavía puedo ver la conexión usando (He agrupación de conexiones desactivado):

SELECT DB_NAME(dbid) as 'Database Name', 
COUNT(dbid) as 'Total Connections' 
FROM sys.sysprocesses WITH (nolock) 
WHERE dbid > 0 
GROUP BY dbid 

EDIT 2: tener algo más de depuración con ayuda que obtuve de aquí; la respuesta fue que alguien codificó una cadena de conexión para ponerla en común. Gracias por toda la ayuda; si pudiera, marcaría todas las respuestas como respuestas.

Respuesta

19

recolección de basura C# 's es no determinista pero el lenguaje proporciona una estructura determinista para la disposición de los recursos de esta manera:

using (SqlConnection connection = new SqlConnection(...)) 
{ 
    // ... 
} 

Esto creará un bloque try/finally que asegurará que el objeto de conexión está dispuesto independientemente de lo sucede en el método. Realmente debería envolver cualquier instancia de tipos que implementen IDisposable en un bloque de uso como este, ya que garantizará una administración de recursos responsable (de recursos no administrados como conexiones de bases de datos) y también le dará el control determinístico que está buscando.

+0

+1 para una respuesta ordenada, mejor que la mía. –

1

Será, después de la recolección de basura hace su trabajo. Lo mismo aplica para abrir una secuencia de archivos para escribir sin cerrarla. Es posible que se "bloquee" a pesar de que los códigos salieron del alcance.

2

Porque C# es un lenguaje recogido de basura, y la recolección de basura no es determinista. El hecho de esto es que su sqlconnection es dispuesta. Simplemente no puedes elegir cuándo.

Las conexiones Sql son un recurso limitado, y es muy posible que pueda crear las suficientes para que se agoten. Escribirlo esta forma:

internal static DataSet SelectDataSet(String commandText, DataBaseEnum dataBase) 
{ 
    var dataset = new DataSet(); 

    using (SqlConnection sqlc = dataBase == DataBaseEnum.ZipCodeDb 
          ? new SqlConnection(ConfigurationManager.AppSettings["ZipcodeDB"]) 
          : new SqlConnection(ConfigurationManager.AppSettings["WeatherDB"])) 
    using (SqlCommand sqlcmd = sqlc.CreateCommand()) 
    { 
     sqlcmd.CommandText = commandText; 
     var adapter = new SqlDataAdapter(sqlcmd.CommandText, sqlc); 
     adapter.Fill(dataset); 

    } 
    return dataset; 
} 

Aunque en este caso puede salirse con la suya, porque el .Fill() method is a strange beast:

Si el IDbConnection se cierra antes de relleno se llama, se abre para recuperar los datos y luego cerrado.

Lo que significa que el Adaptador de Datos debe encargarse de eso, si comienza con una conexión cerrada. Estoy mucho más preocupado de que estés pasando tu comando sql como una cadena simple. Tiene que haber parámetros de usuario en sus consultas de vez en cuando, y esto significa que está concatenando esos datos directamente en la cadena de comandos. ¡No hagas eso! En su lugar, usa la colección Paramters de SqlCommand.

1

Creo que tiene algo que ver con la agrupación SqlConnection.Lo que puede hacer, y lo hacemos a menudo en el trabajo, es envolver toda la llamada en una instrucción de uso que hace que invoque el método dispose(), al cerrar la conexión y deshacerse del objeto

Podría hacer algo como: esto en su lugar:


internal static DataSet SelectDataSet(String commandText, DataBaseEnum dataBase) 
{ 
    var dataset = new DataSet(); 

    using(SqlConnection sqlc = dataBase == DataBaseEnum.ZipCodeDb 
          ? new SqlConnection(ConfigurationManager.AppSettings["ZipcodeDB"]) 
          : new SqlConnection(ConfigurationManager.AppSettings["WeatherDB"])) { 
     SqlCommand sqlcmd = sqlc.CreateCommand(); 
     sqlcmd.CommandText = commandText; 
     var adapter = new SqlDataAdapter(sqlcmd.CommandText, sqlc); 
     adapter.Fill(dataset); 


     return dataset; 
    } 
} 

1

Estoy de acuerdo con todas las respuestas aquí más una conexión puede ser un ámbito más amplio que un simple método. Cuando necesite usar su conexión existente en diferentes lugares, el escenario cambia un poco. Siempre asegúrese de llamar al Dispose para todos los objetos que implementen IDisposable después de que haya terminado de usarlos. Esta es una buena práctica para que no termine con los objetos no utilizados que el recolector de basura no puede decidir qué hacer con ellos.

Cuestiones relacionadas