如何处理来自非 UI 线程的异步 SQL 查询

发布于 2024-12-11 14:30:35 字数 2359 浏览 0 评论 0原文

所有,我已经成功地使用 ADO.NET 来利用类似于下面的示例的异步 SQL 查询。在所示示例中,方法 ExecNonQuery 是从 UI 线程调用的。这很好用,但我想知道如果我从非 UI 线程调用 ExecNonQuery 我将如何处理回调?

笔记。显然,在这种情况下,我会修改 ExecNonQuery,以便相应地处理或删除诸如 this.toolStripStatusLabel1.Text 之类的内容。

public bool ExecNonQuery(string strCmd, string strUserMsg = "")
{
    try
    {
        SqlCommand cmd = new SqlCommand();
        cmd.Connection = conn;
        cmd.CommandText = strCmd;
        cmd.CommandTimeout = 0;
        bIsExecuting = true;
        AsyncCallback callback = new AsyncCallback(HandleCallback);
        cmd.BeginExecuteNonQuery(callback, cmd); 
        return true;
    }
    catch (Exception Ex)
    {
        bIsExecuting = false;
        this.toolStripStatusLabel1.Text = String.Format("Ready (last error: {0})", Ex.Message);
        if (conn != null)
            conn.Close();
    }
    return false;
}

private delegate void DisplayInfoDelegate(string Text);

private void HandleCallback(IAsyncResult result)
{
    try
    {
        // Retrieve the original command object, passed
        // to this procedure in the AsyncState property
        // of the IAsyncResult parameter.

        SqlCommand command = (SqlCommand)result.AsyncState;
        int rowCount = command.EndExecuteNonQuery(result);
        string rowText = " rows affected.";
        if (rowCount == 1)
            rowText = " row affected.";
        rowText = rowCount + rowText;

        // Call the procedure from the form's thread.
        DisplayInfoDelegate del = new DisplayInfoDelegate(DisplayResults);
        this.Invoke(del, rowText);
    }
    catch (Exception ex)
    {
        // Because you are now running code in a separate thread, 
        // if you do not handle the exception here, none of your other
        // code catches the exception.

        // You can create the delegate instance as you 
        // invoke it, like this:
        this.Invoke(new DisplayInfoDelegate(DisplayResults), 
            String.Format("Ready(last error: {0}", ex.Message));
    }
    finally
    {
        bIsExecuting = false;
        if (conn != null)
            conn.Close();
    }
}

private void DisplayResults(string Text)
{
    this.toolStripStatusLabel1.Text = Text;
    this.toolStripProgressBar1.Style = ProgressBarStyle.Blocks;
    this.toolStripProgressBar1.Value = 100;
}

谢谢你的时间。

All, I have successfully used ADO.NET to make use of asynchronous SQL queries similar to the example below. In the example shown the method ExecNonQuery is being invoked from the UI thread. This works well, but I wondered how I would handle the callback if I were to call ExecNonQuery from a non-UI thread?

Note. Clearly, in such a case I would amend ExecNonQuery, so that such things as this.toolStripStatusLabel1.Text were dealt with accordingly, or removed.

public bool ExecNonQuery(string strCmd, string strUserMsg = "")
{
    try
    {
        SqlCommand cmd = new SqlCommand();
        cmd.Connection = conn;
        cmd.CommandText = strCmd;
        cmd.CommandTimeout = 0;
        bIsExecuting = true;
        AsyncCallback callback = new AsyncCallback(HandleCallback);
        cmd.BeginExecuteNonQuery(callback, cmd); 
        return true;
    }
    catch (Exception Ex)
    {
        bIsExecuting = false;
        this.toolStripStatusLabel1.Text = String.Format("Ready (last error: {0})", Ex.Message);
        if (conn != null)
            conn.Close();
    }
    return false;
}

private delegate void DisplayInfoDelegate(string Text);

private void HandleCallback(IAsyncResult result)
{
    try
    {
        // Retrieve the original command object, passed
        // to this procedure in the AsyncState property
        // of the IAsyncResult parameter.

        SqlCommand command = (SqlCommand)result.AsyncState;
        int rowCount = command.EndExecuteNonQuery(result);
        string rowText = " rows affected.";
        if (rowCount == 1)
            rowText = " row affected.";
        rowText = rowCount + rowText;

        // Call the procedure from the form's thread.
        DisplayInfoDelegate del = new DisplayInfoDelegate(DisplayResults);
        this.Invoke(del, rowText);
    }
    catch (Exception ex)
    {
        // Because you are now running code in a separate thread, 
        // if you do not handle the exception here, none of your other
        // code catches the exception.

        // You can create the delegate instance as you 
        // invoke it, like this:
        this.Invoke(new DisplayInfoDelegate(DisplayResults), 
            String.Format("Ready(last error: {0}", ex.Message));
    }
    finally
    {
        bIsExecuting = false;
        if (conn != null)
            conn.Close();
    }
}

private void DisplayResults(string Text)
{
    this.toolStripStatusLabel1.Text = Text;
    this.toolStripProgressBar1.Style = ProgressBarStyle.Blocks;
    this.toolStripProgressBar1.Value = 100;
}

Thanks for you time.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

遇到 2024-12-18 14:30:35

哪个线程运行 ExecNonQuery 对您的回调没有影响 - HandleCallback 仍将在线程池线程上运行。

您已经发现需要进行的更改:如果 ExecNonQuery 未在 UI 线程上运行,则不要直接在 ExecNonQuery 中访问 UI 控件。

缺口

It makes no difference to your callback which thread runs ExecNonQuery - HandleCallback will still be run on a thread pool thread.

You have already spotted the change you need to make: don't access UI controls directly in ExecNonQuery if it is not being run on the UI thread.

Nick

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文