2008-09-25 14 views
5

Lorsque j'essaie d'appeler Close ou Dispose sur un SqlDataReader, j'obtiens une exception de délai expiré. Si vous avez un DbConnection à SQL Server, vous pouvez reproduire vous-même avec:.NET: SqlDataReader.Close ou .Dispose génère une exception Timeout expirée

String CRLF = "\r\n"; 
String sql = 
    "SELECT * " + CRLF + 
    "FROM (" + CRLF + 
    " SELECT (a.Number * 256) + b.Number AS Number" + CRLF + 
    " FROM master..spt_values a," + CRLF + 
    "  master..spt_values b" + CRLF + 
    " WHERE a.Type = 'p'" + CRLF + 
    "  AND b.Type = 'p') Numbers1" + CRLF + 
    " FULL OUTER JOIN (" + CRLF + 
    "  SELECT (print("code sample");a.Number * 256) + b.Number AS Number" + CRLF + 
    "  FROM master..spt_values a," + CRLF + 
    "   master..spt_values b" + CRLF + 
    "  WHERE a.Type = 'p'" + CRLF + 
    "   AND b.Type = 'p') Numbers2" + CRLF + 
    " ON 1=1"; 

DbCommand cmd = connection.CreateCommand(); 
cmd.CommandText = sql; 
DbDataReader rdr = cmd.ExecuteReader(); 
rdr.Close(); 

Si vous appelez reader.Close() ou reader.Dispose(), il lancera une System.Data.SqlClient.SqlException:

  • ErrorCode: -2146232060 (0x80131904)
  • message: « délai d'attente expiré le délai écoulé avant la fin de l'opération ou le serveur ne répond pas. ».

Répondre

13

C'est parce que vous venez d'ouvrir le lecteur de données et que vous ne l'avez pas encore complètement parcouru. vous devrez .Cancel() votre objet DbCommand avant de tenter de fermer un lecteur de données qui n'est pas encore terminé (et la DbConnection aussi). bien sûr, en .Cancel() - votre DbCommand, je ne suis pas sûr de cela mais vous pourriez rencontrer une autre exception. mais vous devriez juste l'attraper si cela arrive.

0

Où lisez-vous réellement les données? Vous créez simplement un lecteur, mais vous ne lisez pas les données. Il est juste une supposition mais peut-être le lecteur a des problèmes pour fermer si vous ne lisez pas;)

DbDataReader rdr = cmd.ExecuteReader(); 
while(rdr.Read()) 
{ 
    int index = rdr.GetInt32(0); 
} 
+0

problème se produit si vous lisez zéro lignes, une ligne ou plusieurs lignes. –

2

Cruizer avait la réponse: appel command.Cancel():

using (DbCommand cmd = connection.CreateCommand()) 
{ 
    cmd.CommandText = sql; 
    using (DbDataReader rdr = cmd.ExecuteReader()) 
    { 
     while (rdr.Read()) 
     { 
      if (WeShouldCancelTheOperation()) 
      { 
      cmd.Cancel(); 
      break; 
      } 
     } 
    }  
} 

Il est également utile de savoir que vous pouvez appeler annuler même si le lecteur a déjà lu toutes les lignes (il ne jette pas une « rien à annuler » exception.)

DbCommand cmd = connection.CreateCommand(); 
try 
{ 
    cmd.CommandText = sql; 
    DbDataReader rdr = cmd.ExecuteReader(); 
    try 
    { 
     while (rdr.Read()) 
     { 
      if (WeShouldCancelTheOperation()) 
      break; 
     } 
     cmd.Cancel(); 
    }  
    finally 
    { 
     rdr.Dispose(); 
    } 
} 
finally 
{ 
    cmd.Dispose(); 
}