如何 运行 .Net: SQLCommand 在它自己的线程上允许用户安全地取消它 - 运行
How to run a .Net: SQLCommand on it's own thread with the ability to allow the user to safely cancel it mid-run
我和我的团队整个星期都在为此苦思冥想。感谢任何帮助。我们正在使用 VB.Net。我们有一个表单,用户将在其中使用 SQLCommand 来执行可能需要几分钟到 运行 的存储过程。我们希望用户能够在 运行ning 期间继续在应用程序中工作,或者能够在处理过程中取消请求。我们研究了线程和后台工作者,以及异步处理。我们无法找到一种解决方案,使我们能够安全无误地取消存储过程和线程的 运行ning。有谁知道如何安全地做到这一点。这是我们目前所拥有的。 *为了安全和尺寸删除了一些细节
Private Sub frmAdhocRptGenerator_Load(sender As Object, e As EventArgs) Handles Me.Load
BackGroundWorkerAdhoc.WorkerReportsProgress = True
BackGroundWorkerAdhoc.WorkerSupportsCancellation = True
End Sub
Private Sub btnExecute_Click(sender As Object, e As EventArgs) Handles btnExecute.Click
If Not BackGroundWorkerAdhoc.IsBusy = True Then BackGroundWorkerAdhoc.RunWorkerAsync()
End Sub
Private Sub BackGroundWorkerAdhoc_DoWork(sender As Object, e As System.ComponentModel.DoWorkEventArgs) Handles BackGroundWorkerAdhoc.DoWork
Try
If BackGroundWorkerAdhoc.CancellationPending = True Then
e.Cancel = True
Exit Sub
End If
Load_n_ExecuteProc(tmpConn)
Catch ex As Exception
ErrorHandler("frmAdhocRptGenerator.subBackGroundWorkerAdhoc_DoWork", ex.ToString)
tmpConn.Close()
End Try
End Sub
Private Function Load_n_ExecuteProc(theConn As SqlConnection) As Boolean
If BackGroundWorkerAdhoc.CancellationPending = True Then
Return False
Exit Function
End If
Try
Dim RunCompleted As Boolean = False
cmdPROVIDER_FINDER = New SqlCommand("SP$PROVIDER_FINDER", tmpConn)
cmdPROVIDER_FINDER.CommandType = CommandType.StoredProcedure
cmdPROVIDER_FINDER.CommandTimeout = 10000
Dim rst As Integer = cmdPROVIDER_FINDER.ExecuteNonQuery()
RunCompleted = rst > -1
Return RunCompleted
Catch ex As Exception
ErrorHandler("frmAdhocRptGenerator.Load_n_ExecuteProc", ex.ToString)
Return False
End Try
End Function
Private Sub BackGroundWorkerAdhoc_RunWorkerCompleted(sender As Object, e As System.ComponentModel.RunWorkerCompletedEventArgs) Handles BackGroundWorkerAdhoc.RunWorkerCompleted
Try
If Success = True Then
Dim filename As String = "AdhocResults" & Now.Month.ToString & "-" & Now.Day.ToString & "-" & Now.Year.ToString
Export2Excel("SELECT * FROM ##PF_PROVIDERS" & currUser.UserID, filename, True)
End If
tmpConn.Close()
Success = False
Catch ex As Exception
ErrorHandler("frmAdhocRptGenerator.BackGroundWorkerAdhoc_RunWorkerCompleted", ex.ToString)
Finally
tmpConn.Close()
End Try
End Sub
Private Sub btnCancel_Click(sender As Object, e As EventArgs) Handles btnCancel.Click
If BackGroundWorkerAdhoc.IsBusy = True Then
BackGroundWorkerAdhoc.CancelAsync()
cmdPROVIDER_FINDER.Cancel()
tmpConn.Close()
tmpConn = Nothing
End If
btnCancel.Enabled = False
End Sub
后台工作者取消并不是什么神奇的方法。它所做的只是将 .CancellationPending 设置为 true。由您的代码以安全的方式实际执行取消,然后退出 DoWork 处理程序。
您现有的取消代码只有在您的用户在线程开始之前取消时才有效,这不太可能,因此您可以将其删除。
If BackGroundWorkerAdhoc.CancellationPending = True Then
Return False
Exit Function
End If
而是从您的 UI 线程发出 SqlCommand.Cancel 调用。然后该命令将终止,然后您将照常退出 DoWork。如果您要过早地终止 sql 命令,我建议您在丢弃的 SqlConnection 上执行此操作,因此我创建了一个新命令。
Private Sub BackGroundWorkerAdhoc_DoWork(sender As Object, e As System.ComponentModel.DoWorkEventArgs) Handles BackGroundWorkerAdhoc.DoWork
Try
Using myNewConn As New SqlConnection(...)
Load_n_ExecuteProc(myNewConn)
End Using
Catch ex As Exception
ErrorHandler("frmAdhocRptGenerator.subBackGroundWorkerAdhoc_DoWork", ex.ToString)
End Try
End Sub
Private Function Load_n_ExecuteProc(theConn As SqlConnection) As Boolean
Try
cmdPROVIDER_FINDER = New SqlCommand("SP$PROVIDER_FINDER", tmpConn)
cmdPROVIDER_FINDER.CommandType = CommandType.StoredProcedure
cmdPROVIDER_FINDER.CommandTimeout = 10000
Dim rst As Integer = cmdPROVIDER_FINDER.ExecuteNonQuery()
return = rst > -1
Catch ex As Exception
ErrorHandler("frmAdhocRptGenerator.Load_n_ExecuteProc", ex.ToString)
Finally
cmdPROVIDER_FINDER = Nothing
End Try
End Function
Public Sub CancelSqlCommand()
Dim cmd = cmdPROVIDER_FINDER
If cmd isnot Nothing cmd.Cancel()
End Sub
我和我的团队整个星期都在为此苦思冥想。感谢任何帮助。我们正在使用 VB.Net。我们有一个表单,用户将在其中使用 SQLCommand 来执行可能需要几分钟到 运行 的存储过程。我们希望用户能够在 运行ning 期间继续在应用程序中工作,或者能够在处理过程中取消请求。我们研究了线程和后台工作者,以及异步处理。我们无法找到一种解决方案,使我们能够安全无误地取消存储过程和线程的 运行ning。有谁知道如何安全地做到这一点。这是我们目前所拥有的。 *为了安全和尺寸删除了一些细节
Private Sub frmAdhocRptGenerator_Load(sender As Object, e As EventArgs) Handles Me.Load
BackGroundWorkerAdhoc.WorkerReportsProgress = True
BackGroundWorkerAdhoc.WorkerSupportsCancellation = True
End Sub
Private Sub btnExecute_Click(sender As Object, e As EventArgs) Handles btnExecute.Click
If Not BackGroundWorkerAdhoc.IsBusy = True Then BackGroundWorkerAdhoc.RunWorkerAsync()
End Sub
Private Sub BackGroundWorkerAdhoc_DoWork(sender As Object, e As System.ComponentModel.DoWorkEventArgs) Handles BackGroundWorkerAdhoc.DoWork
Try
If BackGroundWorkerAdhoc.CancellationPending = True Then
e.Cancel = True
Exit Sub
End If
Load_n_ExecuteProc(tmpConn)
Catch ex As Exception
ErrorHandler("frmAdhocRptGenerator.subBackGroundWorkerAdhoc_DoWork", ex.ToString)
tmpConn.Close()
End Try
End Sub
Private Function Load_n_ExecuteProc(theConn As SqlConnection) As Boolean
If BackGroundWorkerAdhoc.CancellationPending = True Then
Return False
Exit Function
End If
Try
Dim RunCompleted As Boolean = False
cmdPROVIDER_FINDER = New SqlCommand("SP$PROVIDER_FINDER", tmpConn)
cmdPROVIDER_FINDER.CommandType = CommandType.StoredProcedure
cmdPROVIDER_FINDER.CommandTimeout = 10000
Dim rst As Integer = cmdPROVIDER_FINDER.ExecuteNonQuery()
RunCompleted = rst > -1
Return RunCompleted
Catch ex As Exception
ErrorHandler("frmAdhocRptGenerator.Load_n_ExecuteProc", ex.ToString)
Return False
End Try
End Function
Private Sub BackGroundWorkerAdhoc_RunWorkerCompleted(sender As Object, e As System.ComponentModel.RunWorkerCompletedEventArgs) Handles BackGroundWorkerAdhoc.RunWorkerCompleted
Try
If Success = True Then
Dim filename As String = "AdhocResults" & Now.Month.ToString & "-" & Now.Day.ToString & "-" & Now.Year.ToString
Export2Excel("SELECT * FROM ##PF_PROVIDERS" & currUser.UserID, filename, True)
End If
tmpConn.Close()
Success = False
Catch ex As Exception
ErrorHandler("frmAdhocRptGenerator.BackGroundWorkerAdhoc_RunWorkerCompleted", ex.ToString)
Finally
tmpConn.Close()
End Try
End Sub
Private Sub btnCancel_Click(sender As Object, e As EventArgs) Handles btnCancel.Click
If BackGroundWorkerAdhoc.IsBusy = True Then
BackGroundWorkerAdhoc.CancelAsync()
cmdPROVIDER_FINDER.Cancel()
tmpConn.Close()
tmpConn = Nothing
End If
btnCancel.Enabled = False
End Sub
后台工作者取消并不是什么神奇的方法。它所做的只是将 .CancellationPending 设置为 true。由您的代码以安全的方式实际执行取消,然后退出 DoWork 处理程序。
您现有的取消代码只有在您的用户在线程开始之前取消时才有效,这不太可能,因此您可以将其删除。
If BackGroundWorkerAdhoc.CancellationPending = True Then
Return False
Exit Function
End If
而是从您的 UI 线程发出 SqlCommand.Cancel 调用。然后该命令将终止,然后您将照常退出 DoWork。如果您要过早地终止 sql 命令,我建议您在丢弃的 SqlConnection 上执行此操作,因此我创建了一个新命令。
Private Sub BackGroundWorkerAdhoc_DoWork(sender As Object, e As System.ComponentModel.DoWorkEventArgs) Handles BackGroundWorkerAdhoc.DoWork
Try
Using myNewConn As New SqlConnection(...)
Load_n_ExecuteProc(myNewConn)
End Using
Catch ex As Exception
ErrorHandler("frmAdhocRptGenerator.subBackGroundWorkerAdhoc_DoWork", ex.ToString)
End Try
End Sub
Private Function Load_n_ExecuteProc(theConn As SqlConnection) As Boolean
Try
cmdPROVIDER_FINDER = New SqlCommand("SP$PROVIDER_FINDER", tmpConn)
cmdPROVIDER_FINDER.CommandType = CommandType.StoredProcedure
cmdPROVIDER_FINDER.CommandTimeout = 10000
Dim rst As Integer = cmdPROVIDER_FINDER.ExecuteNonQuery()
return = rst > -1
Catch ex As Exception
ErrorHandler("frmAdhocRptGenerator.Load_n_ExecuteProc", ex.ToString)
Finally
cmdPROVIDER_FINDER = Nothing
End Try
End Function
Public Sub CancelSqlCommand()
Dim cmd = cmdPROVIDER_FINDER
If cmd isnot Nothing cmd.Cancel()
End Sub