2009-06-25 13 views
5

Entonces, ¿por qué esto nunca llega a la función de devolución de llamada?sql problema de consulta asíncrona

using System; 
using System.Collections.Generic; 
using System.ComponentModel; 
using System.Data; 
using System.Drawing; 
using System.Linq; 
using System.Text; 
using System.Windows.Forms; 
using System.Data.SqlClient; 

namespace sqlAsyncTesting { 
    public partial class Form1 : Form { 

    public Form1() { 
     InitializeComponent(); 
    } 

    private void button1_Click(object sender, EventArgs e) { 
     using (SqlConnection conn = new SqlConnection(@"Data Source = bigapple; Initial Catalog = master; Integrated Security = SSPI; Asynchronous Processing = true;")) { 
      conn.Open(); 
      SqlCommand cmd = new SqlCommand(@"WAITFOR DELAY '00:03'; Select top 3 * from sysobjects;", conn); 
      IAsyncResult result = cmd.BeginExecuteReader(new AsyncCallback(HandleCallback), cmd, CommandBehavior.CloseConnection); 
     } 
    } 

    private void HandleCallback(IAsyncResult result) { 
     SqlDataReader dr; 
     SqlCommand _this = (SqlCommand)result.AsyncState; 

     if (result.IsCompleted) { 
      dr = _this.EndExecuteReader(result); 
     } else dr = null; 

     DataTable dt = new DataTable(); 
     DataSet ds = new DataSet(); 

     dt.Load(dr); 
     ds.Tables.Add(dt); 
     dr.Close(); 
     Complete(ds); 
    } 

    private void Complete(DataSet ds) { 
     string output = string.Empty; 
     foreach (DataColumn c in ds.Tables[0].Columns) { 
      output += c.ColumnName + "\t"; 
     } 
     output += "\r\n"; 
     foreach (DataRow dr in ds.Tables[0].Rows) { 
      foreach (object i in dr.ItemArray) { 
       output += i.ToString() + "\t"; 
      } 
      output += "\r\n"; 
     } 
    } 
} 

}

Respuesta

3

Algunos puntos me di cuenta:

  1. El método de devolución de llamada se llama sólo después de que me quita el WAITFOR RETRASO stmt.
  2. No hay necesidad de sondear para obtener el resultado. Se completó, porque el método de devolución de llamada se activa solo después de que se completa el proceso asincrónico .
  3. No es necesario establecer explícitamente dr = null en la parte else porque de forma predeterminada será nulo.
  4. Debe manejar InvalidOperationException y ArgumentException en el método HandleCallback.
  5. En la devolución de llamada del controlador cada vez que se llama al EndExecuteReader() I sigue obteniendo la excepción "La operación asincrónica ya ha finalizado ." Así que nunca pude obtener el resultado en dr.

Si enfrenta el problema mencionado en el punto no. 5, puede usar la siguiente solución alternativa implementada mediante el uso de delegados asíncronos en lugar del BeginExecuteReader incorporado() y EndExecuteReader(). En la solución a continuación también, el control se devolverá inmediatamente a la próxima línea después de invocar al delegado, tal como sucede en el caso de BeginExecuteReader().

solución alternativa:

public partial class Form2 : Form 
{ 
    public Form2() 
    { 
     InitializeComponent(); 
    } 

    private delegate DataSet GetDSDelegate(string query); 

    private void button1_Click(object sender, EventArgs e) 
    { 
     GetDSDelegate del = new GetDSDelegate(GetDataSetAsync); 
     del.BeginInvoke(@"Select top 3 * from table1;", null, null); 
    } 

    private DataSet GetDataSetAsync(string query) 
    { 
     DataSet ds; 
     using (SqlConnection conn = new SqlConnection(@"Data Source = mmmmm000011\sqlexpress; Initial Catalog = SOExamples; Integrated Security = SSPI; Asynchronous Processing = true;")) 
     using (SqlCommand cmd = new SqlCommand(query, conn)) 
     { 
      try 
      { 
       conn.Open(); 
       SqlDataReader dr = cmd.ExecuteReader(); 

       DataTable dt = new DataTable(); 
       ds = new DataSet(); 

       dt.Load(dr); 
       ds.Tables.Add(dt); 
       dr.Close(); 
       Complete(ds); 
      } 
      finally 
      { 
       if (conn.State != ConnectionState.Closed) 
        conn.Close(); 
      } 
     } 
     MessageBox.Show("Done!!!"); 
     return ds; 
    } 

    private void Complete(DataSet ds) 
    { 
     ... 
    } 
} 
+0

Sí. # 5 fue la opción que terminé usando. :) ¡Gracias por la gran respuesta! – bitcycle

+0

Mención no. Gracias por la gran pregunta: D –

3

Creo que la conexión se cierra antes de que el lector podría funcionar ...

using (SqlConnection conn = new SqlConnection(@"Data Source = bigapple; Initial Catalog = master; Integrated Security = SSPI; Asynchronous Processing = true;")) 

Intente cambiar a ...

SqlConnection conn = new SqlConnection(@"Data Source = bigapple; Initial Catalog = master; Integrated Security = SSPI; Asynchronous Processing = true;"); 
     conn.Open(); 
     SqlCommand cmd = new SqlCommand(@"WAITFOR DELAY '00:03'; Select top 3 * from sysobjects;", conn); 
     IAsyncResult result = cmd.BeginExecuteReader(new AsyncCallback(HandleCallback), cmd, CommandBehavior.CloseConnection); 

Por el ¿De qué forma este código espera 3 minutos? Porque pausar durante 3 segundos, ¿no debería ser WAITFOR DELAY '0: 0: 3'?

+0

Fredrik Me cambió el retraso a 0: 0: 5 y siendo mi devolución de llamada duerma ser despedido. Solo cuando elimino el retraso de espera, puedo depurar la devolución de llamada. ¿Has probado depurar? Es bastante interesante. –