web-dev-qa-db-fra.com

Dans un bloc "using", un SqlConnection est-il fermé en cas de retour ou d'exception?

Première question:
Dis que j'ai

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

    string storedProc = "GetData";
    SqlCommand command = new SqlCommand(storedProc, connection);
    command.CommandType = CommandType.StoredProcedure;
    command.Parameters.Add(new SqlParameter("@EmployeeID", employeeID));

    return (byte[])command.ExecuteScalar();
}

La connexion est-elle fermée? Parce que techniquement, nous n'allons jamais au dernier } comme nous return avant.

Deuxième question:
Cette fois, j'ai:

try
{
    using (SqlConnection connection = new SqlConnection(connectionString))
    {
        int employeeID = findEmployeeID();

        connection.Open();
        SqlCommand command = new SqlCommand("UpdateEmployeeTable", connection);
        command.CommandType = CommandType.StoredProcedure;
        command.Parameters.Add(new SqlParameter("@EmployeeID", employeeID));
        command.CommandTimeout = 5;

        command.ExecuteNonQuery();
    }
}
catch (Exception) { /*Handle error*/ }

Maintenant, disons quelque part dans la try nous obtenons une erreur et elle est interceptée. La connexion est-elle toujours fermée? Parce que, encore une fois, nous ignorons le reste du code dans la variable try et allons directement à l’instruction catch.

Est-ce que je pense trop linéairement à la façon dont using fonctionne? Par exemple, Dispose() est-il simplement appelé lorsque nous quittons la portée de using?

131
Marcus
  1. Oui
  2. Oui.

Quoi qu'il en soit, lorsque vous quittez le bloc using (soit par succès, soit par erreur), il est fermé.

Bien que je pense que ce serait meilleur à organiser comme ça parce que c'est beaucoup plus facile de voir ce qui va se passer, même pour le nouveau programmeur de maintenance qui le supportera plus tard:

using (SqlConnection connection = new SqlConnection(connectionString)) 
{    
    int employeeID = findEmployeeID();    
    try    
    {
        connection.Open();
        SqlCommand command = new SqlCommand("UpdateEmployeeTable", connection);
        command.CommandType = CommandType.StoredProcedure;
        command.Parameters.Add(new SqlParameter("@EmployeeID", employeeID));
        command.CommandTimeout = 5;

        command.ExecuteNonQuery();    
    } 
    catch (Exception) 
    { 
        /*Handle error*/ 
    }
}
172
David

Oui aux deux questions. L'instruction using est compilée dans un bloc try/finally

using (SqlConnection connection = new SqlConnection(connectionString))
{
}

est le même que

SqlConnection connection = null;
try
{
    connection = new SqlConnection(connectionString);
}
finally
{
   if(connection != null)
        ((IDisposable)connection).Dispose();
}

Edit: Fixation de la distribution sur Jetable http://msdn.Microsoft.com/en-us/library/yh598w02.aspx

44
Ryan Pedersen

Voici mon modèle. Tout ce dont vous avez besoin pour sélectionner les données d'un serveur SQL. La connexion est fermée et supprimée et les erreurs de connexion et d'exécution sont interceptées.

string connString = System.Configuration.ConfigurationManager.ConnectionStrings["CompanyServer"].ConnectionString;
string selectStatement = @"
    SELECT TOP 1 Person
    FROM CorporateOffice
    WHERE HeadUpAss = 1 AND Title LIKE 'C-Level%'
    ORDER BY IntelligenceQuotient DESC
";
using (SqlConnection conn = new SqlConnection(connString))
{
    using (SqlCommand comm = new SqlCommand(selectStatement, conn))
    {
        try
        {
            conn.Open();
            using (SqlDataReader dr = comm.ExecuteReader())
            {
                if (dr.HasRows)
                {
                    while (dr.Read())
                    {
                        Console.WriteLine(dr["Person"].ToString());
                    }
                }
                else Console.WriteLine("No C-Level with Head Up Ass Found!? (Very Odd)");
            }
        }
        catch (Exception e) { Console.WriteLine("Error: " + e.Message); }
        if (conn.State == System.Data.ConnectionState.Open) conn.Close();
    }
}

* Révisé: 2015-11-09 *
Comme suggéré par NickG; Si trop d'accolades vous gênent, formatez comme ceci ...

using (SqlConnection conn = new SqlConnection(connString))
   using (SqlCommand comm = new SqlCommand(selectStatement, conn))
   {
      try
      {
         conn.Open();
         using (SqlDataReader dr = comm.ExecuteReader())
            if (dr.HasRows)
               while (dr.Read()) Console.WriteLine(dr["Person"].ToString());
            else Console.WriteLine("No C-Level with Head Up Ass Found!? (Very Odd)");
      }
      catch (Exception e) { Console.WriteLine("Error: " + e.Message); }
      if (conn.State == System.Data.ConnectionState.Open) conn.Close();
   }

Encore une fois, si vous travaillez pour les jeux EA ou DayBreak, vous pouvez également vous passer de sauts de ligne, car ceux-ci sont réservés aux personnes qui doivent revenir consulter votre code plus tard et qui s'en soucie réellement. Ai-je raison? Je veux dire 1 ligne au lieu de 23 signifie que je suis un meilleur programmeur, non?

using (SqlConnection conn = new SqlConnection(connString)) using (SqlCommand comm = new SqlCommand(selectStatement, conn)) { try { conn.Open(); using (SqlDataReader dr = comm.ExecuteReader()) if (dr.HasRows) while (dr.Read()) Console.WriteLine(dr["Person"].ToString()); else Console.WriteLine("No C-Level with Head Up Ass Found!? (Very Odd)"); } catch (Exception e) { Console.WriteLine("Error: " + e.Message); } if (conn.State == System.Data.ConnectionState.Open) conn.Close(); }

Ouf ... OK. J'ai sorti ça de mon système et je me suis amusé pendant un moment. Continuer.

15
ShaneLS

Eliminer est simplement appelé lorsque vous quittez le champ d'utilisation. Le but de "l’utilisation" est de donner aux développeurs un moyen sûr de s’assurer que les ressources sont éliminées.

De MSDN :

Une instruction using peut être quittée lorsque la fin de l'instruction using est atteinte ou si une exception est levée et que le contrôle quitte le bloc d'instructions avant la fin de l'instruction.

5
overstood

Using génère un try/finally autour de l'objet alloué et appelle Dispose() pour vous.

Cela vous évite d'avoir à créer manuellement le bloc try/finally et à appeler Dispose()

5
VoodooChild

Dans votre premier exemple, le compilateur C # traduira l’instruction using en ce qui suit:

SqlConnection connection = new SqlConnection(connectionString));

try
{
    connection.Open();

    string storedProc = "GetData";
    SqlCommand command = new SqlCommand(storedProc, connection);
    command.CommandType = CommandType.StoredProcedure;
    command.Parameters.Add(new SqlParameter("@EmployeeID", employeeID));

    return (byte[])command.ExecuteScalar();
}
finally
{
    connection.Dispose();
}

Enfin, les instructions seront toujours appelées avant le retour d’une fonction et la connexion sera toujours fermée/supprimée.

Ainsi, dans votre deuxième exemple, le code sera compilé comme suit:

try
{
    try
    {
        connection.Open();

        string storedProc = "GetData";
        SqlCommand command = new SqlCommand(storedProc, connection);
        command.CommandType = CommandType.StoredProcedure;
        command.Parameters.Add(new SqlParameter("@EmployeeID", employeeID));

        return (byte[])command.ExecuteScalar();
    }
    finally
    {
        connection.Dispose();
    }
}
catch (Exception)
{
}

L'exception sera interceptée dans la déclaration finally et la connexion sera fermée. L'exception ne sera pas vue par la clause de capture externe.

3
Kerri Brown

J'ai écrit deux en utilisant des instructions à l'intérieur d'un try/catch block et je pouvais voir que l'exception était interceptée de la même manière si elle est placée dans la partie interne à l'aide de l'instruction comme ShaneLS exemple .

     try
     {
       using (var con = new SqlConnection(@"Data Source=..."))
       {
         var cad = "INSERT INTO table VALUES (@r1,@r2,@r3)";

         using (var insertCommand = new SqlCommand(cad, con))
         {
           insertCommand.Parameters.AddWithValue("@r1", atxt);
           insertCommand.Parameters.AddWithValue("@r2", btxt);
           insertCommand.Parameters.AddWithValue("@r3", ctxt);
           con.Open();
           insertCommand.ExecuteNonQuery();
         }
       }
     }
     catch (Exception ex)
     {
       MessageBox.Show("Error: " + ex.Message, "UsingTest", MessageBoxButtons.OK, MessageBoxIcon.Error);
     }

Peu importe où est le try/catch placé, l'exception sera interceptée sans problèmes.

1
WhySoSerious