Невозможно прервать восстановление базы данных - PullRequest
1 голос
/ 26 февраля 2012

Я хотел бы предоставить пользователю кнопку Отмена - чтобы прервать процесс восстановления. Для этого в обработчике события Restore.PercentComplete я проверяю, нажал ли пользователь кнопку Отмена, и вызываю Restore.Abort(). Но это не помогает:

Исключение SMO:

Не удалось восстановить сервер 'MICHAEL7'.
Возникла исключительная ситуация при выполнении оператора или пакета Transact-SQL.
Трассировка стека: в Microsoft.SqlServer.Management.Smo.Restore.SqlRestore (Server srv)

БД остается в режиме «Восстановление» навсегда. Вот соответствующий код:

using Microsoft.SqlServer.Management.Common;
using Microsoft.SqlServer.Management.Smo;

private volatile bool _CancelRestore = false;
private Restore _RestoreDB;
private Server _myServer;
private Database _currentDatabase;

// user hits Cancel buttton
public void CancelRestore()
{
    _CancelRestore = true;
}

// Restore.PercentComplete event handler
private static void CompletionStatusInPercent(object sender, PercentCompleteEventArgs args) 
{
    if (_CancelRestore)
    {
        _RestoreDB.Abort();

          // Disable the kills to let some time to Abort()

        // Stop all processes running on the _currentDatabase database
        // _myServer.KillAllProcesses(_currentDatabase.Name);

        // Stop the _currentDatabase database
        // NOTE: it is a temp name DB: I do not restore over my application DB!
        // _myServer.KillDatabase(_currentDatabase.Name);
    }
    else
    {
        Console.Clear();
        Console.WriteLine("Percent completed: {0}%.", args.Percent);
    }
}

Функция резервного копирования / восстановления была реализована с помощью этой статьи: Резервное копирование и восстановление базы данных SQL Server 2005 с использованием C # и .NET 2.0

Спасибо.

1 Ответ

1 голос
/ 11 июня 2015

Я знаю, что это старый вопрос, но я застрял с той же проблемой, и я нашел решение, которое работает для меня.

Вместо KillDatabase я использую следующее:

sqlRestore.Abort();
sqlRestore.Wait(); //This will wait until the restore operation is canceled
Database db = _server.Database(databaseName);
if (db != null)
    db.Drop(); // This will drop the "half" restored Database

Должен сказать, что я использую SqlRestoreAsync.

KillDatabase () уничтожит все соединения, поэтому KillAllProcesses () здесь устарел.

Ее мой полный код:

public async Task<bool> Restore(string backupFile, string databaseName, IProgress<int> progress, CancellationToken ct)
{
    Restore sqlRestore = null;

    bool result = await Task.Run(() =>
    {
        try
        {
            var deviceItem = new BackupDeviceItem(backupFile, DeviceType.File);
            sqlRestore = new Restore
            {
                Action = RestoreActionType.Database,
                Database = databaseName,
                Partial = false,
                ReplaceDatabase = true,
                PercentCompleteNotification = 1
            };
            sqlRestore.PercentComplete += (s, e) => progress.Report(e.Percent);
            sqlRestore.Devices.Add(deviceItem);

            if (_server.Databases[databaseName] != null)
                _server.KillAllProcesses(databaseName);

            sqlRestore.SqlRestoreAsync(_server);

            while (sqlRestore.AsyncStatus.ExecutionStatus == ExecutionStatus.InProgress)
            {
                ct.ThrowIfCancellationRequested();
                Thread.Sleep(500);
            }

            if (sqlRestore.AsyncStatus.ExecutionStatus == ExecutionStatus.Succeeded)
            {
                Database db = _server.Databases[databaseName];
                if (db != null)
                    db.SetOnline();

                _server.Refresh();
                return true;
            }
            return false;
        }
        catch (OperationCanceledException)
        {
            sqlRestore.Abort();
            sqlRestore.Wait();
            Database db = _server.Databases[databaseName];
            if (db != null)
                db.Drop();
            return true;
        }
        catch (ConnectionFailureException)
        {
            return false;
        }
        catch (Exception ex)
        {
            _server.KillDatabase(databaseName);
            return false;
        }
    }, ct);
    return result;
}
...