简体   繁体   English

如何运行.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

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM