Search code examples
c#.netsql-serverado.netasynchronous

When is SqlCommand.StatementCompleted supposed to fire?


I'm trying to write a simple winforms application that executes a SQL SELECT statement asynchronous. When the sql server starts returning results, I want to execute an event handler I've wired up to the SqlCommand's StatementCompleted event.

The form contains two buttons, a textbox, and a label. When button1 is clicked, I create the SqlCommand and wire up the event handler, then I open the SqlConnection and call BeginExecuteReader in order to start the asynchronous operation. I set my label to show the command is executing.

In the event handler, I simply set the label to show the command is finished.

When button 2 is clicked, I change the label to show we're processing the results. Then I call EndExecuteReader and assign its return value to a new SqlDataReader which I then process.

What I see is that the event handler doesn't get called when the command is ready. In stead, it gets called when my code finishes processing the reader returned by EndExecuteReader.

Am I missing something here? Do I misinterpret the intended use of the event? I've tried to find an example of StatementCompleted, but I could only find general descriptions of it, no working code. The example at the SqlCommand.BeginExecuteReader page at MSDN uses a loop and waits for the IAsyncResult.IsCompleted property to be true. I would expect that at the same time that property gets true, the StatementCompleted event fires.

public Form1() {
    InitializeComponent();
}

private IAsyncResult iAsyncResult;
private SqlCommand sqlCommand;

private void statementCompleted(object sender,
                                StatementCompletedEventArgs e) {
    label1.Text = "Statement completed";
}

private void button1_Click(object sender, EventArgs e) {
    var northWindConnection =
        new SqlConnection(
            "Data Source=.\\SqlExpress;Initial Catalog=Northwind;" +
            "Integrated Security=True;" +
            "asynchronous processing=true");
    sqlCommand = new SqlCommand("WAITFOR DELAY '00:00:05';" +
                                " SELECT * FROM [Order Details]",
                                northWindConnection);
    sqlCommand.StatementCompleted += statementCompleted;
    northWindConnection.Open();
    iAsyncResult = sqlCommand.BeginExecuteReader();
    label1.Text = "Executing";
}

private void button2_Click(object sender, EventArgs e) {
    label1.Text = "Not waiting anymore, reading";
    var results = new StringBuilder();
    var reader = sqlCommand.EndExecuteReader(iAsyncResult);
    while (reader.Read()) {
        for (int i = 0; i < reader.FieldCount; i++) {
            results.Append(reader[i].ToString() + "\t");
        }
        results.Append(Environment.NewLine);
    }
    reader.Close();
    sqlCommand.Connection.Close();
    textBox1.Text = results.ToString();
}

Solution

  • Adding this for anyone that might run across this question since it was asked months ago with no answers provided.

    The StatementCompleted event isn't useful in applying an async call pattern against SqlCommand. It does get fired but only during the call to EndExecuteReader which is basically too late. If you want to implement an async call pattern in general, this MSDN article has an excellent explanation of how it can be done. The sample code in the BeginExecuteReader documentation shows the correct usage of SqlCommand in an async mode.