2017-08-07 8 views
-1

J'ai 2 SqlCommand, l'un d'eux est imbriqué. Pourquoi cela ne me permet pas d'émettre la deuxième SqlCommand (j'utilise une commande SQLCommand séparée)? Il donne une erreur "Il y a déjà un DataReader ouvert associé à cette commande qui doit être fermé en premier." . Si j'utilise un SqlConnection séparé, ça va.Ne pas autoriser SQLCommand imbriqué?

SqlCommand cmd = new SqlCommand(qry, cn); 

SqlDataReader rd = cmd.ExecuteReader(); 

while (rd.Read()) 
{ 
     ....  
     try 
     { 
      SqlCommand cmd2 = new SqlCommand(qry2, cn); 
      cmd2.ExecuteNonQuery(); 
     } 
     catch (Exception e) 
     { 
      // I get this error here 
      // System.Data; There is already an open DataReader associated with this Command which must be closed first. 
     }   
} 
+1

Vous avez besoin d'une instance de connexion supplémentaire pour exécuter une autre requête avec la même chaîne de connexion pour les requêtes simultanées. Comme il peut être impossible d'arrêter 'DataReader' lors de l'exécution d'une autre requête, pensez à insérer le contenu' DataReader' dans un 'DataTable', fermez la première connexion et rouvrez-le lors de l'itération du contenu' DataTable'. –

Répondre

1

Le message est évident: vous ne pouvez pas utiliser le même connexion pour différents cas SqlCommand en même temps tout en DataReader est encore ouvert. L'explication de l'instance SqlDataReader déjà dit que:

Alors que le SqlDataReader est utilisé, le SqlConnection associé est occupé à servir SqlDataReader et aucune autre opération peut être effectuée sur le SqlConnection autre que fermer. C'est le cas jusqu'à ce que la méthode Close de SqlDataReader soit appelée. Par exemple, vous ne pouvez pas extraire les paramètres de sortie avant d'avoir appelé Fermer.

La solution commune à ce problème est d'utiliser MultipleActiveResultSets=True sur la chaîne de connexion:

<add name="ConnectionName" connectionString="[connection string];MultipleActiveResultSets=True" ... /> 

Ensuite, utilisez DataTable à la place itérer DataReader directement:

var dt = new DataTable(); 
dt.Load(rd); 

foreach (DataRow row in dt.Rows) 
{ 
    // other stuff 

    try 
    { 
     SqlCommand cmd2 = new SqlCommand(qry2, cn); 
     cmd2.ExecuteNonQuery(); 
    } 
    catch (Exception e) 
    { 
     // throw exception 
    } 
} 

De plus, vous pouvez mettre simple vérification si la connexion précédente est toujours ouverte (ie desservant DataReader) en utilisant SqlConnection.State propriété:

// close if connection still open 
if (cn.State == ConnectionState.Open) 
{ 
    cn.Close(); 
} 

// open if connection already closed 
if (cn.State == ConnectionState.Closed) 
{ 
    cn.Open(); 
} 

Les contrôles simples ci-dessus doivent être placés sur toute partie du code qui demande SqlConnection.

+0

Merci pour les explications claires – Squirrel