[英]How to run a .Net: SQLCommand on it's own thread with the ability to allow the user to safely cancel it mid-run
My team and I have been banging our heads around this all week. 我和我的团队整整一周都在努力奋斗。 Appreciate any help.
感谢任何帮助。 We are using VB.Net.
我们正在使用VB.Net。 We have a form where the user will use a SQLCommand to execute a stored procedure that can take several minutes to run.
我们有一个表单,用户将使用SQLCommand执行一个存储过程,该过程可能需要几分钟才能运行。 We would like the user to be able to continue working in the application while it's running or to be able to cancel the request in the middle of processing.
我们希望用户能够在应用程序运行时继续工作,或者能够在处理过程中取消请求。 We have looked into threading and background workers, and asynchronous processing.
我们研究了线程和后台工作程序以及异步处理。 We cannot find a solution that will allow us to cancel the running of the stored procedure and thread safely without errors.
我们找不到能使我们安全地取消存储过程和线程运行而不会出错的解决方案。 Does anyone know how to do this safely.
有谁知道如何安全地做到这一点。 Here's what we have so far.
到目前为止,这就是我们所拥有的。 *some details removed for security and size
*为了安全性和尺寸而删除了一些详细信息
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
Background worker cancellation isn't a magic method. 取消后台工作人员并不是一个神奇的方法。 All it does is sets .CancellationPending to true.
它所做的只是将.CancellationPending设置为true。 It's up to your code to actually do the cancellation in a safe way and then exit the DoWork handler.
由您的代码实际以一种安全的方式执行取消,然后退出DoWork处理程序。
Your existing code for cancellation can only work if your user cancels before the thread starts, that's unlikely so you can remove it. 您现有的取消代码仅在用户在线程启动之前取消的情况下才有效,这不太可能,因此您可以将其删除。
If BackGroundWorkerAdhoc.CancellationPending = True Then
Return False
Exit Function
End If
Instead issue an SqlCommand.Cancel call from your UI thread. 而是从您的UI线程发出SqlCommand.Cancel调用。 Then the command will terminate and then you'll exit DoWork as normal.
然后该命令将终止,然后您将照常退出DoWork。 If you're going to be terminating an sql command prematurely I'd recommend doing it on a throw away SqlConnection hence why I've created a new one.
如果您要过早终止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
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.