2009-06-25 4 views
5

Alors, pourquoi cela n'est-il jamais arrivé à la fonction de rappel?sql async query problem

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"; 
     } 
    } 
} 

}

Répondre

3

Quelques points que je remarqué:

  1. La méthode de rappel a été appelé seulement après que j'enlevé le WAITFOR DELAY stmt.
  2. Il n'est pas nécessaire d'interroger pour result.IsCompleted, car la méthode de rappel est déclenchée uniquement après que le traitement asynchrone est terminé.
  3. Pas besoin de définir explicitement dr = null dans la partie else car par défaut, sera null.
  4. Vous devez gérer InvalidOperationException et ArgumentException dans la méthode HandleCallback .
  5. Dans le rappel de handle à chaque fois, le EndExecuteReader() a été appelé I a gardé l'exception "L'opération asynchrone a déjà terminé ." Donc, je n'ai jamais pu obtenir le résultat en dr.

Si vous rencontrez le problème répertorié au point no. 5, vous pouvez utiliser la solution alternative suivante implémentée en utilisant des délégués asynchrones plutôt que les BeginExecuteReader() et EndExecuteReader() intégrés. Dans la solution ci-dessous également, le contrôle sera immédiatement renvoyé à la ligne suivante après l'appel du délégué, comme dans le cas de BeginExecuteReader().

Autre solution:

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

Oui. # 5 était l'option que j'ai fini par utiliser. :) Merci pour la bonne réponse! – bitcycle

+0

Ne mentionnez pas. Merci pour la bonne question: D –

3

Je pense que la connexion est fermée avant que le lecteur pourrait fonctionner ...

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

Essayez de changer à ...

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); 

Par manière que ce code attend pendant 3 minutes? Parce que faire une pause pendant 3 secondes ne devrait-il pas être WAITFOR DELAY '0: 0: 3'?

+0

Fredrik I a changé le délai à 0: 0: 5 et toujours mon rappel ne marche pas me faire virer. Ce n'est que lorsque je supprime le délai waitf delay que je peux déboguer en callback. Avez-vous essayé debuggin? C'est très intéressant. –