.NET - 如何将BackgroundWorker与CMD.executenonquery一起使用

时间:2013-11-06 13:31:24

标签: sql vb.net multithreading backgroundworker

在我的Windows窗体中,我有这个查询,大约有2,000,000行。 执行查询会冻结界面,大约需要60秒才能完成。

有没有办法可以设置一个进度条,通知用户任务正在进行中?

我是多线程的新手,所以任何帮助都会受到赞赏。

这是花时间的代码:

断点冻结在cmd.executenonquery()

Public Sub InsertNumberswithMsgID(ByVal messageID As Integer, ByVal tableName As String) 

    Dim cmd As SqlCommand = Nothing

    Try
        cmd = New SqlCommand(("dbo.[InsertNumbers_withMsgID]"), cn)
        cmd.CommandType = CommandType.StoredProcedure
        cmd.Parameters.AddWithValue("@tablename", tableName)
        cmd.Parameters.AddWithValue("@msgid", messageID)
        cmd.CommandTimeout = 6000
        If Not cn Is Nothing And cn.State = ConnectionState.Closed Then cn.Open()
        cmd.ExecuteNonQuery()

    Catch ex As SqlException

    Catch ex As Exception

    Finally
        If Not cn Is Nothing And cn.State = ConnectionState.Open Then cn.Close()
        If Not cmd Is Nothing Then cmd.Dispose()
    End Try

End Function

2 个答案:

答案 0 :(得分:1)

Arman提到的article确实是一个很好的起点 - 将它用作代码的骨架,并将函数调用放在sleep命令所在的位置。

但是在您提供的示例中,由于存储过程在一个步骤中执行所有操作并在完成后返回,因此实际上没有办法更新进度栏中的进度。

因此,通过这种方式,您可以在执行前显示0%,然后在完成后显示100%。

或者您必须更改存储过程,以便可以更精细地调用它,即每次处理10%的行,然后返回 - 这将允许您更新进度条(仅在您被允许时才有效)将它分成多个要插入的行块 - 如果你需要在一个事务中将它们保存在一起,那么你当然不能这样做。)

或者,您可以考虑使用进度条的Marquee样式,如here所述。在这种情况下,您根本不需要更新百分比值。

答案 1 :(得分:0)

无论您如何生成工作线程,您需要做的第一件事是禁用UI的部分,这些部分将允许用户再次发出相同的请求,否则用户可能会多次单击按钮,因为所有用户都不耐烦。

要生成您的其他线程以在后台执行SQL工作,请使用BeginExecuteNonQuery函数并将命令对象作为状态变量传递,如果您关心返回受影响的行数。 在通话结束后立即显示进度动画或消息。

然后,在BeginExecuteNonQuery的回调方法中,停止/隐藏进度动画/文本。

以下是一个例子:

Public Sub InsertNumberswithMsgID(ByVal messageID As Integer, ByVal tableName As String) 

    Dim cmd As SqlCommand = Nothing

    Try
        cmd = New SqlCommand(("dbo.[InsertNumbers_withMsgID]"), cn)
        cmd.CommandType = CommandType.StoredProcedure
        cmd.Parameters.AddWithValue("@tablename", tableName)
        cmd.Parameters.AddWithValue("@msgid", messageID)
        cmd.CommandTimeout = 6000
        If Not cn Is Nothing And cn.State = ConnectionState.Closed Then cn.Open()
        cmd.BeginExecuteNonQuery(FinishInsertingNumbersWithMsgId, cmd)
        ShowYourProgressAnimation()
    Catch ex As SqlException

    Catch ex As Exception

    Finally
        If Not cn Is Nothing And cn.State = ConnectionState.Open Then cn.Close()
        If Not cmd Is Nothing Then cmd.Dispose()
    End Try

End Sub

Private Sub FinishInsertingNumbersWithMsgId(ByVal ar As IAsyncResult)
    Dim cmd As SqlCommand = ar.AsyncState
    cmd.EndExecuteNonEquery(ar)
    HideYourProgressAnimation()
End Sub