什么时候SqlCommand.StatementCompleted应该开火?

时间:2011-01-20 09:10:56

标签: c# .net sql-server ado.net asynchronous

更新我是否必须澄清我的问题?我很惊讶地看到我在两周内没有得到任何评价,评论或回答。


我正在尝试编写一个简单的winforms应用程序,该应用程序异步执行SQL SELECT语句。当sql server开始返回结果时,我想执行一个事件处理程序,我已连接到SqlCommand的StatementCompleted事件。

表单包含两个按钮,一个文本框和一个标签。单击button1时,我创建SqlCommand并连接事件处理程序,然后打开SqlConnection并调用BeginExecuteReader以启动异步操作。我设置标签以显示命令正在执行。

在事件处理程序中,我只需设置标签即可显示命令已完成。

单击按钮2时,我更改标签以显示我们正在处理结果。然后我调用EndExecuteReader并将其返回值分配给新的SqlDataReader,然后我处理它。

我看到的是,当命令准备好时,不会调用事件处理程序。相反,当我的代码完成处理EndExecuteReader返回的阅读器时,它会被调用。

我在这里遗漏了什么吗?我是否误解了事件的预期用途?我试图找到一个StatementCompleted的例子,但我只能找到它的一般描述,没有工作代码。 SqlCommand.BeginExecuteReader page at MSDN的示例使用循环并等待IAsyncResult.IsCompleted属性为true。我希望在属性获得同时,StatementCompleted事件会触发。

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

3 个答案:

答案 0 :(得分:2)

事件的顺序如下:

  1. 调用SqlCommand.BeginExecuteReader(callback, stateObject)将T-SQL发送到SQL Server,命令开始执行。
  2. 当数据首次可用时,系统会调用提供给AsyncCallback的{​​{1}}。
  3. 回调调用BeginExecuteReader()以获取对EndExecuteReader()对象的引用。
  4. 您使用SqlDataReader来阅读查询结果。这可以是一行,也可以是数百万行。 在返回所有请求的数据之前,查询未完成。
  5. 重复其他结果集(如果有)。
  6. 调用SqlDataReader事件 - 但前提是查询/存储过程未使用StatementCompleted
  7. 换句话说,当T-SQL完全完成时调用SET NOCOUNT ON,包括所有相关的数据传输。

答案 1 :(得分:1)

为可能遇到此问题的任何人添加此项,因为几个月前它被问到没有提供答案。

StatementCompleted事件在对SqlCommand应用异步调用模式时没有用。它确实被解雇但只是在调用EndExecuteReader期间,这基本上已经太晚了。如果您想要实现一般的异步调用模式,this MSDN article可以很好地解释它是如何完成的。 BeginExecuteReader documentation中的示例代码显示了异步模式下SqlCommand的正确用法。

答案 2 :(得分:0)

我怀疑这种行为的线索是事件的“ StatementCompletedEventArgs”参数包含属性“ RecordCount”,该属性是受语句影响的行数。
在实际数据全部发送完之后,MS SqlServer(以及之前的Sybase SqlServer)将受影响的行数作为单独的“消息”(宽松地使用术语)返回。

另外,请注意:一个Sql Command可以由许多SQL语句组成,每个SQL语句都可以影响许多行,因此返回许多“受影响的行”。因此,我认为对于给定的SQL命令,该事件可能会触发多次;或根本没有使用SET NOCOUNT ON。

相关问题