我正在{230}数据库的SqlCeEngine.Upgrade()
调用期间获得大量磁盘I / O - 正如预期的那样。
问题在于即使它在BackgroundWorker
线程中运行,它仍然会锁定UI。我试过Async/Await
无济于事。 (FWIW,我将在时间允许的情况下升级代码。)
摘录代码如下。
有什么想法吗?
Friend Class MainForm
Private Sub itmRestore_Click(Sender As Object, e As EventArgs) Handles itmRestore.Click
If Utils.MsgQuestion(Bl.Messages.DB_RESTORE_PROMPT) = MsgBoxResult.Yes Then
ofdRestore.InitialDirectory = Bl.Registry.DownloadFolder
ofdRestore.FileName = String.Empty
If ofdRestore.ShowDialog = Windows.Forms.DialogResult.OK Then
prgCopy.SourcePath = ofdRestore.FileName
prgCopy.TargetPath = Db.Utils.DatabasePath
prgCopy.ActionText = "Restoring the database..."
Me.Cursor = Cursors.WaitCursor
bgwBackup.RunWorkerAsync(Bl.BackgroundJobs.RestoreDatabase)
End If
End If
End Sub
Private Sub bgwBackup_DoWork(Sender As Object, e As DoWorkEventArgs) Handles bgwBackup.DoWork
bgwStartup.ReportProgress(-1, "Loading...")
Select Case DirectCast(e.Argument, Bl.BackgroundJobs)
Case Bl.BackgroundJobs.BackupDatabase : Bl.Jobs.Database.BackupDatabase(prgCopy, e)
Case Bl.BackgroundJobs.RestoreDatabase : Bl.Jobs.Database.RestoreDatabase(prgCopy, e)
Case Bl.BackgroundJobs.CheckDatabaseVersion : Bl.Jobs.Database.CheckDatabaseVersion(e)
Case Bl.BackgroundJobs.UpgradeDatabase : Bl.Jobs.Database.UpgradeDatabase(e)
Case Bl.BackgroundJobs.UpdateDatabaseSchema : Bl.Jobs.Database.UpdateDatabaseSchema(Sender, e)
End Select
End Sub
Private Sub bgwBackup_ProgressChanged(sender As Object, e As ProgressChangedEventArgs) Handles bgwBackup.ProgressChanged
UpdateProgress(e.ProgressPercentage, e.UserState)
End Sub
Private Sub bgwBackup_RunWorkerCompleted(sender As Object, e As RunWorkerCompletedEventArgs) Handles bgwBackup.RunWorkerCompleted
Dim eNextJob As Bl.BackgroundJobs
Dim oManager As Bl.Jobs.Manager
oManager = e.Result
If e.Error Is Nothing Then
Select Case oManager.CurrentJob
Case Bl.BackgroundJobs.BackupDatabase
eNextJob = Bl.BackgroundJobs.None
UpdateProgress(0)
Utils.MsgInformation(Bl.Messages.DB_BACKUP_SUCCESS.ToFormat(vbCrLf, sfdBackup.FileName))
Case Bl.BackgroundJobs.RestoreDatabase
eNextJob = Bl.BackgroundJobs.CheckDatabaseVersion
UpdateProgress(0)
Utils.MsgInformation(Bl.Messages.DB_RESTORE_SUCCESS)
Case Bl.BackgroundJobs.CheckDatabaseVersion
If oManager.Continue Then
eNextJob = Bl.BackgroundJobs.UpdateDatabaseSchema
Else
eNextJob = Bl.BackgroundJobs.UpgradeDatabase
Utils.MsgInformation(Bl.Messages.DB_UPGRADE_NOTICE)
UpdateProgress(-1, "Upgrading the database...")
End If
Case Bl.BackgroundJobs.UpgradeDatabase
eNextJob = Bl.BackgroundJobs.UpdateDatabaseSchema
UpdateProgress(0)
Utils.MsgInformation(Bl.Messages.DB_UPGRADE_SUCCESS)
Case Bl.BackgroundJobs.UpdateDatabaseSchema
eNextJob = Bl.BackgroundJobs.None
End Select
Else
Utils.MsgCritical(Bl.Messages.DB_RESTORE_ERROR.ToFormat(vbCrLf, e.Error.ToString))
eNextJob = Bl.BackgroundJobs.None
End If
If eNextJob = Bl.BackgroundJobs.None Then
UpdateProgress(0, "Ready")
txtLastName.Focus()
Me.Cursor = Cursors.Default
Else
bgwBackup.RunWorkerAsync(eNextJob)
End If
End Sub
Private Sub UpdateProgress(ProgressPercentage As Integer)
UpdateProgress(ProgressPercentage, String.Empty)
End Sub
Private Sub UpdateProgress(ProgressPercentage As Integer, StatusText As String)
If ProgressPercentage = -1 Then
If prgProgress.Style <> ProgressBarStyle.Marquee Then
prgProgress.Style = ProgressBarStyle.Marquee
prgProgress.Value = 0
End If
Else
prgProgress.Style = ProgressBarStyle.Blocks
prgProgress.Value = Min(ProgressPercentage, 100)
End If
If Trim(StatusText).Length > 0 Then
lblStatus.Text = StatusText
End If
End Sub
End Class
Namespace Bl
Namespace Jobs
Friend Class Manager
Public CurrentJob As BackgroundJobs
Public [Continue] As Boolean
Public Sub New(CurrentJob As BackgroundJobs, [Continue] As Boolean)
Me.CurrentJob = CurrentJob
Me.Continue = [Continue]
End Sub
End Class
Friend Class Database
Public Shared Sub CheckDatabaseVersion(e As DoWorkEventArgs)
e.Result = New Manager(e.Argument, Db.Utils.CheckDatabaseVersion)
End Sub
Public Shared Sub UpgradeDatabase(e As DoWorkEventArgs)
Db.Utils.UpgradeDatabase()
e.Result = New Manager(e.Argument, True)
End Sub
Public Shared Sub UpdateDatabaseSchema(Worker As BackgroundWorker, e As DoWorkEventArgs)
If Db.Versioning.SchemaVersionStatus = Db.Enums.SchemaVersionStates.Newer Then
Throw New ApplicationException("An incompatible database version has been detected. A newer version of Matrix is required.")
Else
Db.Versioning.UpdateSchema(Worker, e)
e.Result = New Manager(e.Argument, True)
End If
End Sub
Public Shared Sub BackupDatabase(Copier As ProgressCopy.ProgressCopy, e As DoWorkEventArgs)
Copier.Start()
e.Result = New Manager(e.Argument, True)
End Sub
Public Shared Sub RestoreDatabase(Copier As ProgressCopy.ProgressCopy, e As DoWorkEventArgs)
Db.Utils.ArchiveDatabase()
Copier.Start()
e.Result = New Manager(e.Argument, True)
End Sub
End Class
End Namespace
Friend Enum BackgroundJobs
None
UpgradeDatabase
UpdateDatabaseSchema
ValidateCityCode
CheckSubscription
CheckOptionsWizard
CheckDatabaseVersion
BackupDatabase
RestoreDatabase
End Enum
End Namespace
Namespace Db
Friend Class Utils
Public Shared Sub UpgradeDatabase()
Dim _
sSource,
sTarget As String
sSource = ArchiveDatabase()
sTarget = DatabasePath
Try
With New SqlCeEngine(SqlCe.Connection.ConnectionString(sSource))
.Upgrade(SqlCe.Connection.ConnectionString(sTarget))
End With
Catch ex As Exception
Throw New ApplicationException(ex.Message, ex)
End Try
End Sub
Public Shared Function ArchiveDatabase() As String
Dim oFile As FileInfo
Dim _
sTarget,
sNow As String
Dim _
oSource, _
oTarget _
As DirectoryInfo
Do
sNow = Now.ToFileNameString(DateStringOptions.IncludeTime)
oSource = New DirectoryInfo(DatabaseFolder)
sTarget = Path.Combine(oSource.FullName, "Deleted {0}".ToFormat(sNow))
oTarget = New DirectoryInfo(sTarget)
Loop While oTarget.Exists
oTarget.Create()
For Each oFile In oSource.GetFiles
oFile.MoveTo(Path.Combine(oTarget.FullName, oFile.Name))
Next
ArchiveDatabase = Path.Combine(oTarget.FullName, Db.Utils.DatabaseFile)
End Function
End Class
End Namespace
答案 0 :(得分:2)
你正在使用背景工作者。来自DoWork
:
您必须小心不要操纵
DoWork
事件处理程序中的任何用户界面对象。而是通过BackgroundWorker
事件与用户界面进行通信。
看起来您正在使用DoWork
处理程序操作UI。
答案 1 :(得分:1)
我暂时坚持使用BackgroundWorker,100%明确表示升级是在单独的池线程上运行。
然后我会准确地调查前景在它挂起时要做的事情。您可以考虑使用ProcDump。
我的猜测是,在某些时候,前景是对数据库层进行一些调用,然后由于升级正在运行而阻塞。不要忘记这个调用可能是几乎任何事情的结果(计时器,鼠标移动等),但是一旦它被阻止它将停止整个消息泵,然后挂起UI。