2009-11-12 18 views
8

Estoy tratando de extraer algunos datos binarios de una base de datos y escribirlos en archivos PDF. En su mayor parte, esto va muy bien, pero la fila ocasional de datos arroja un error particular:¿La excepción de Timeout hace que se cierre SqlDataReader?

Tiempo de espera caducado. El período de tiempo de espera transcurrido antes de la finalización de la operación o el servidor no responde.

Tenga en cuenta que esto solo ocurre en un puñado de filas y nunca es aleatorio. Las mismas filas siempre lanzan la excepción. No estoy seguro de por qué se lanza la excepción, pero estoy de acuerdo con saltear las filas que sí causan problemas y continuar. Mi problema, sin embargo, es que cuando atrapo la excepción y trato de pasar a la siguiente fila, me encuentro con otra excepción:

InvalidOperationException - Intento no válido de llamar a Read cuando el lector está cerrado.

¿Significa esto que el lector se cierra automáticamente tan pronto como se encuentra con una excepción? ¿Cómo voy a proceder a la siguiente fila sin dramas?

 while (sdrReader.Read()) // Second exception happens here 
     { 
      try 
      { 
       byte[] byteData = new Byte[(sdrReader.GetBytes(0, 0, null, 0, int.MaxValue))]; // first exception happens here 
       sdrReader.GetBytes(0, 0, byteData, 0, byteData.Length); 
       string strOutputFileName = sdrReader.GetInt32(1).ToString() + ".pdf"; 
       msMemoryStreams = new MemoryStream(); 
       msMemoryStreams.Write(byteData, 0, byteData.Length); 
       byte[] byteArray = msMemoryStreams.ToArray(); 

       msMemoryStreams.Flush(); 
       msMemoryStreams.Close(); 

       writeByteArrayToFile(byteData, txtFilesPath.Text + "\\" + strOutputFileName); 
      } 
      catch (Exception e) 
      { 
       Logger.Write("Document failed to convert: " + e.Message); 
      } 
     } 

Seguimiento de la pila, conforme a lo solicitado -

at System.Data.SqlClient.SqlInternalConnection.OnError(SqlException exception, Boolean breakConnection) 
at System.Data.SqlClient.TdsParser.ThrowExceptionAndWarning(TdsParserStateObject stateObj) 
    at System.Data.SqlClient.TdsParserStateObject.ReadSniError(TdsParserStateObject stateObj, UInt32 error) 
    at System.Data.SqlClient.TdsParserStateObject.ReadSni(DbAsyncResult asyncResult, TdsParserStateObject stateObj) 
    at System.Data.SqlClient.TdsParserStateObject.ReadNetworkPacket() 
    at System.Data.SqlClient.TdsParserStateObject.ReadBuffer() 
    at System.Data.SqlClient.TdsParserStateObject.ReadByteArray(Byte[] buff, Int32 offset, Int32 len) 
    at System.Data.SqlClient.TdsParser.ReadSqlValue(SqlBuffer value, SqlMetaDataPriv md, Int32 length, TdsParserStateObject stateObj) 
    at System.Data.SqlClient.SqlDataReader.ReadColumnData() 
    at System.Data.SqlClient.SqlDataReader.ReadColumn(Int32 i, Boolean setTimeout) 
    at System.Data.SqlClient.SqlDataReader.GetSqlBinary(Int32 i) 
    at System.Data.SqlClient.SqlDataReader.GetBytesInternal(Int32 i, Int64 dataIndex, Byte[] buffer, Int32 bufferIndex, Int32 length) 
    at System.Data.SqlClient.SqlDataReader.GetBytes(Int32 i, Int64 dataIndex, Byte[] buffer, Int32 bufferIndex, Int32 length) 
    at Pdf2Rtf.Form1.Read() in F:\Code\Pdf2Rtf\Pdf2Rtf\Pdf2Rtf\Form1.cs:line 77 
    at Pdf2Rtf.Form1.btnRead_Click(Object sender, EventArgs e) in F:\Code\Pdf2Rtf\Pdf2Rtf\Pdf2Rtf\Form1.cs:line 24 
    at System.Windows.Forms.Control.OnClick(EventArgs e) 
    at System.Windows.Forms.Button.OnClick(EventArgs e) 
    at System.Windows.Forms.Button.OnMouseUp(MouseEventArgs mevent) 
    at System.Windows.Forms.Control.WmMouseUp(Message& m, MouseButtons button, Int32 clicks) 
    at System.Windows.Forms.Control.WndProc(Message& m) 
    at System.Windows.Forms.ButtonBase.WndProc(Message& m) 
    at System.Windows.Forms.Button.WndProc(Message& m) 
    at System.Windows.Forms.Control.ControlNativeWindow.OnMessage(Message& m) 
    at System.Windows.Forms.Control.ControlNativeWindow.WndProc(Message& m) 
    at System.Windows.Forms.NativeWindow.DebuggableCallback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam) 
    at System.Windows.Forms.UnsafeNativeMethods.DispatchMessageW(MSG& msg) 
    at System.Windows.Forms.Application.ComponentManager.System.Windows.Forms.UnsafeNativeMethods.IMsoComponentManager.FPushMessageLoop(Int32 dwComponentID, Int32 reason, Int32 pvLoopData) 
    at System.Windows.Forms.Application.ThreadContext.RunMessageLoopInner(Int32 reason, ApplicationContext context) 
    at System.Windows.Forms.Application.ThreadContext.RunMessageLoop(Int32 reason, ApplicationContext context) 
    at System.Windows.Forms.Application.Run(Form mainForm) 
    at Pdf2Rtf.Program.Main() in F:\Code\Pdf2Rtf\Pdf2Rtf\Pdf2Rtf\Program.cs:line 18 
    at System.AppDomain._nExecuteAssembly(Assembly assembly, String[] args) 
    at System.AppDomain.ExecuteAssembly(String assemblyFile, Evidence assemblySecurity, String[] args) 
    at Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly() 
    at System.Threading.ThreadHelper.ThreadStart_Context(Object state) 
    at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state) 
    at System.Threading.ThreadHelper.ThreadStart() 

Respuesta

12

Parece que su SqlCommand se está agotando: cuando llame al ExecuteReader, el comando asociado permanece abierto y será vulnerable a los tiempos de espera hasta que termine de leer. Como se dice en la documentación SqlCommand.CommandTimeout:

Esta propiedad es el acumulado tiempo de espera para toda la red lee durante la ejecución del comando o el procesamiento de los resultados . Aún puede producirse un tiempo de espera después de que se devuelva la primera fila, y no incluye el tiempo de procesamiento del usuario, único tiempo de lectura de la red.

Cuando el comando se agota, cierra el lector, del cual no se puede recuperar.

Lo primero que debe hacer para solucionar este problema es aumentar el número CommandTimeout de manera espectacular, solo para asegurarse de que puede continuar.

A continuación, si no lo ha hecho, puede ayudar a utilizar la sobrecarga de ExecuteReader que le permite especificar un CommandBehavior, y pasar CommandBehavior.SequentialAccess (por la recomendación en el tema de MSDN "Retrieving Large Data (ADO.NET) ").

Finalmente, también podría intentar dividir las lecturas en fragmentos de registros.

+0

Resultó que todo lo que necesitaba era aumentar el tiempo de espera (mente, usted, tuve que aumentarlo a unos 10 minutos). Algunos de los documentos que estoy extrayendo son gigantes! Gracias;) – Paulie

1

Si el error SQL Gravedad es inferior a 17, se puede establecer SqlConnection.FireInfoMessageEventOnUserErrors = true para manejar la excepción como una advertencia. Cualquier cosa mayor que Severity 17 va a close the connection pase lo que pase.

Cuestiones relacionadas