0

VB.NET 2.0:

VB.NETアプリケーションからSQLサーバーにバックアップコマンドを発行しています。送信するメッセージをキャプチャして、複数行のテキストボックスに追加しています。

ただし、私がやろうとしているのは、アプリケーションがGUI制御イベントに応答し続けることを許可することです(主に、ユーザーが出力ウィンドウのサイズを変更したり、バックアップをキャンセルしたりできるようにするためです)。だから私はを使用BeginExecuteReaderしてループでスピンしますApplication.DoEvents()。しかし、バックアップがprintステートメントの発行を開始するとすぐに、が取得され、IAsyncResult.IsCompleted = TrueにドロップダウンしEndExecuteReader、GUIが再びロックされたようです。バックアップコマンドが完了するまでループにとどまり、それでもそれらの出力ステートメントを取得してGUIの応答性を維持するにはどうすればよいですか?ありがとう。

これが私のコードです:

' Enable retrieve print statements from the server'
AddHandler oConn.InfoMessage, AddressOf LogToBufferHandler

strSQL &= vbNewLine & "begin try"
strSQL &= vbNewLine & " declare @BackupName as varchar(255)"
strSQL &= vbNewLine & " declare @BackupDesc as varchar(255)"
strSQL &= vbNewLine & " declare @backupTime as varchar(50)"
strSQL &= vbNewLine & " set @backupTime = (select convert(datetime, getdate(), 100))"
strSQL &= vbNewLine & " set @BackupName = (SELECT '[' + db_name() + '] Full Backup')"
strSQL &= vbNewLine & " set @BackupDesc = (SELECT 'Automated full backup of [' + db_name() + '] on ' + @backupTime + '.')"
strSQL &= vbNewLine & " "
strSQL &= vbNewLine & " BACKUP DATABASE [#Database#]"
strSQL &= vbNewLine & " TO DISK = @BackupFullPath"
strSQL &= vbNewLine & " WITH stats,"
strSQL &= vbNewLine & "      NAME = @BackupName,"
strSQL &= vbNewLine & "      DESCRIPTION = @BackupDesc;"
strSQL &= vbNewLine & " select [IsSuccessful] = 1"
strSQL &= vbNewLine & " end try"
strSQL &= vbNewLine & " begin catch"
strSQL &= vbNewLine & " SELECT [IsSuccessful] = 0"
strSQL &= vbNewLine & " end catch"

'Workaround: Backup Database requires the name of the object, not a string'
'            and I dont want to use dynamic SQL.'
strSQL = strSQL.Replace("#Database#", sb.InitialCatalog)

oConn.Open()
oCmd = New SqlCommand()
oCmd.Connection = oConn
oCmd.CommandText = strSQL
oCmd.CommandType = CommandType.Text
oCmd.Parameters.AddWithValue("@BackupFullPath", backupFullPath)
oCmd.CommandTimeout = 60 * 5

'Spin until complete, cancel, or timeout'
Dim result As IAsyncResult = oCmd.BeginExecuteReader(CommandBehavior.CloseConnection)
While Not result.IsCompleted
    Application.DoEvents()
    If blnCancel Then
        oCmd.Cancel()
    End If
    System.Threading.Thread.Sleep(50)
End While
Try
    oDataReader = oCmd.EndExecuteReader(result)
    oDataTable.Load(oDataReader)

    'Get results'
    ' (unfourtunately, you cannot do BeginExecuteScalar ASync in .Net 2.0,'
    ' so we are using a DataTable first column, row)'
    If oDataTable IsNot Nothing _
    AndAlso oDataTable.Rows.Count > 0 _
    AndAlso oDataTable.Columns.Contains("IsSuccessful") _
    AndAlso oDataTable.Rows(0).Item("IsSuccessful") = 1 Then
        eBackupResult = BackupStatus.Succeeded
        returnPath = backupFullPath 'Only set return path if the backup succeeded'
    Else
        eBackupResult = BackupStatus.Failed
    End If
Catch ex As Exception
    If Not ex.Message.Contains("cancelled by user") Then Throw ex
    eBackupResult = BackupStatus.Canceled
End Try
4

3 に答える 3

1

ポーリングループ(DoEvents)は、多くの理由で悪と見なされます。BackgroundWorker厄介なBegin-poll-Endスキームに切り替えて、それを放棄するのがおそらく最も簡単な方法です。

それを保持したい場合は、ここにバグがあります:リーダーを受け入れるのは迅速ですが、それはすべての結果が到着したことを意味するわけではありません(説明させてください:1TBのデータをクエリした場合はどうなりますか?-読み取りは長いプロセスです)。Read非同期(ポーリング)の方法でも行う必要があります。今、物事は手に負えなくなります。ただそれを放棄します。

つまり、oDataTable.Load修正が難しいブロッキングです。

于 2012-12-07T18:08:07.800 に答える
0

BackGroundWorkerとReportProgress

BackgroundWorkerクラス

于 2012-12-07T17:54:49.027 に答える
0

これにはTASKSを使用できます。タスクは、概念的にはスレッドに似ています。コードをタスクに入れることで、メインスレッドは実行を継続できます(これは、ユーザー入力を受け取り、サイズ変更コマンドに応答するスレッドです)。

これは、タスクについて詳しく説明し、VB.NETの例がある記事です。

http://www.dotnetcurry.com/ShowArticle.aspx?ID=491

楽しむ!

于 2012-12-07T17:31:44.367 に答える