103 votes

Est-il nécessaire de fermer et d'éliminer manuellement SqlDataReader ?

Je travaille avec un code ancien et il y a de nombreuses instances de SqlDataReader qui ne sont jamais fermés ou éliminés. La connexion est fermée, mais je ne sais pas s'il est nécessaire de gérer le lecteur manuellement.

Cela peut-il entraîner un ralentissement des performances ?

147voto

Codebrain Points 2430

Essayez d'éviter d'utiliser des lecteurs de ce type :

SqlConnection connection = new SqlConnection("connection string");
SqlCommand cmd = new SqlCommand("SELECT * FROM SomeTable", connection);
SqlDataReader reader = cmd.ExecuteReader();
connection.Open();
if (reader != null)
{
      while (reader.Read())
      {
              //do something
      }
}
reader.Close(); // <- too easy to forget
reader.Dispose(); // <- too easy to forget
connection.Close(); // <- too easy to forget

Au lieu de cela, il faut les envelopper dans des déclarations d'utilisation :

using(SqlConnection connection = new SqlConnection("connection string"))
{

    connection.Open();

    using(SqlCommand cmd = new SqlCommand("SELECT * FROM SomeTable", connection))
    {
        using (SqlDataReader reader = cmd.ExecuteReader())
        {
            if (reader != null)
            {
                while (reader.Read())
                {
                    //do something
                }
            }
        } // reader closed and disposed up here

    } // command disposed here

} //connection closed and disposed here

La déclaration d'utilisation garantira l'élimination correcte de l'objet et la libération des ressources.

Si vous l'oubliez, vous laissez le soin au ramasseur d'ordures de faire le ménage, ce qui peut prendre un certain temps.

30 votes

Vous n'avez pas besoin de l'instruction .Close() dans les deux exemples : elle est gérée par l'appel .Dispose().

1 votes

Cet exemple ne montre pas que la connexion sous-jacente est fermée/disposée, ce qui est le plus important.

1 votes

Je ne comprends pas pourquoi le lecteur serait nul après "cmd.ExecuteReader" ?

66voto

Joe Points 60749

Notez que l'élimination d'un SqlDataReader instancié à l'aide de SqlCommand.ExecuteReader() aura pour effet de no fermer/éliminer la connexion sous-jacente.

Il existe deux modèles courants. Dans le premier, le lecteur est ouvert et fermé dans le cadre de la connexion :

using(SqlConnection connection = ...)
{
    connection.Open();
    ...
    using(SqlCommand command = ...)
    {
        using(SqlDataReader reader = command.ExecuteReader())
        {
            ... do your stuff ...
        } // reader is closed/disposed here
    } // command is closed/disposed here
} // connection is closed/disposed here

Il est parfois pratique de demander à une méthode d'accès aux données d'ouvrir une connexion et de renvoyer un lecteur. Dans ce cas, il est important que le lecteur renvoyé soit ouvert à l'aide de CommandBehavior.CloseConnection, de sorte que la fermeture/disposition du lecteur entraîne la fermeture de la connexion sous-jacente. Le modèle ressemble à ceci :

public SqlDataReader ExecuteReader(string commandText)
{
    SqlConnection connection = new SqlConnection(...);
    try
    {
        connection.Open();
        using(SqlCommand command = new SqlCommand(commandText, connection))
        {
            return command.ExecuteReader(CommandBehavior.CloseConnection);
        }
    }
    catch
    {
        // Close connection before rethrowing
        connection.Close();
        throw;
    }
}

et le code appelant n'a plus qu'à se débarrasser du lecteur :

using(SqlDataReader reader = ExecuteReader(...))
{
    ... do your stuff ...
} // reader and connection are closed here.

1 votes

Dans le deuxième extrait de code où la méthode renvoie un SqlDataReader, la commande n'est pas éliminée. Est-ce que c'est correct et est-ce que c'est correct de disposer de la commande (en l'enfermant dans un bloc using) et de renvoyer ensuite le lecteur ?

1 votes

@alwayslearning c'est exactement le scénario que j'ai...... pouvez-vous fermer/disposer de la SqlCommand lorsque vous retournez le SqlDataReader à l'appelant ?

2 votes

Ce n'est pas bon. Si vous VRAIMENT ne peut supporter d'utiliser using puis appeler dispose dans l'application finally {} bloc après la prise. De la manière dont cela est écrit, les commandes réussies ne seraient jamais fermées ou éliminées.

15voto

Kon Points 16125

Pour plus de sécurité, enveloppez chaque objet SqlDataReader dans un objet utiliser la déclaration .

1 votes

C'est tout à fait normal. Toutefois, l'absence de déclaration d'utilisation fait-elle réellement une différence en termes de performances ?

2 votes

Une instruction d'utilisation revient à envelopper le code du DataReader dans un bloc try..finally..., avec la méthode close/dispose dans la section finally. Fondamentalement, elle "garantit" que l'objet sera éliminé correctement.

2 votes

Cela provient directement du lien que j'ai fourni : "L'instruction using garantit que Dispose est appelé même si une exception se produit pendant que vous appelez des méthodes sur l'objet."

6voto

J.W. Points 8135

Enveloppez simplement votre SQLDataReader avec l'instruction "using". Cela devrait résoudre la plupart de vos problèmes.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X