Настройка однопользовательского режима для восстановления резервной копии

У меня есть следующая функция:

public void RestoreDatabase(String databaseName, String backUpFile, 
                            String serverName, String userName, String password)
{
    SqlConnection.ClearAllPools();
    ServerConnection connection = new ServerConnection
                                          (serverName, userName, password);
    Server sqlServer = new Server(connection);
    Restore rstDatabase = new Restore();
    rstDatabase.Action = RestoreActionType.Database;
    rstDatabase.Database = databaseName;
    BackupDeviceItem bkpDevice = new BackupDeviceItem
                                         (backUpFile, DeviceType.File);
    rstDatabase.Devices.Add(bkpDevice);
    rstDatabase.ReplaceDatabase = true;
    rstDatabase.SqlRestore(sqlServer);
}

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

        private string singleUserCmd = "alter database db-name set SINGLE_USER";
        private string multiUserCmd = "alter database db-name  set MULTI_USER";

        private void SetSingleUser(bool singleUser, 
                                   SqlConnectionStringBuilder csb)
        {
            string v;
            if (singleUser)
            {
                v = singleUserCmd.Replace("db-name", csb.InitialCatalog);
            }
            else
            {
                v = multiUserCmd.Replace("db-name", csb.InitialCatalog);
            }
            SqlCommand cmd = new SqlCommand(v, new SqlConnection
                                                     (csb.ToString()));
            try
            {
                cmd.Connection.Open();
                cmd.ExecuteNonQuery();
            }
            finally
            {
                cmd.Connection.Close();
            }
        }

Кажется, проблема в том, что однопользовательский режим предназначен для этого соединения, не позволяя никому делать что-либо еще. Мне нужно, чтобы это было для соединения, которое восстанавливает резервную копию.

2 ответа

Решение

Восстановление должно происходить в соединении, которое переводит БД в однопользовательский режим, так почему бы не заставить вашу функцию SetSingleUser возвращать открытое SqlConnection, в котором она выполнялась, и затем ваш код Восстановления принимает и использует то же открытое соединение.

private string singleUserCmd = "alter database db-name set SINGLE_USER";
private string multiUserCmd = "alter database db-name  set MULTI_USER";

private SqlConnection SetSingleUser(bool singleUser, SqlConnectionStringBuilder csb)
{
    string v;
    if (singleUser)
    {
        v = singleUserCmd.Replace("db-name", csb.InitialCatalog);
    }
    else
    {
        v = multiUserCmd.Replace("db-name", csb.InitialCatalog);
    }
    SqlConnection connection = new SqlConnection(csb.ToString());
    SqlCommand cmd = new SqlCommand(v, connection);

        cmd.Connection.Open();
        cmd.ExecuteNonQuery();

    return connection;
}

Ответ Дакворта совершенно правильный. но вы также можете сделать это следующим образом:

using System;
using System.Data.SqlClient;
using Microsoft.SqlServer.Management.Common;
using Microsoft.SqlServer.Management.Smo;

public class DatabaseRestoreHelper
{
    private const string _SingleUserCmd = "ALTER DATABASE {0} SET SINGLE_USER WITH ROLLBACK IMMEDIATE";
    private const string _MultiUserCmd = "ALTER DATABASE {0} SET MULTI_USER";

    public static void RestoreDatabase(string connectionString, string backupSetPath, bool verify)
    {
        SqlConnectionStringBuilder cb = new SqlConnectionStringBuilder(connectionString);
        string database = cb.InitialCatalog;

        cb.InitialCatalog = "master";

        SqlConnection sqlConnection = new SqlConnection(cb.ConnectionString);
        ServerConnection serverConnection = new ServerConnection(sqlConnection);

        try
        {
            //Make Database Single User
            serverConnection.ExecuteNonQuery(String.Format(_SingleUserCmd, database));

            Server server = new Server(serverConnection);
            Restore restore = new Restore();

            BackupDeviceItem destination = new BackupDeviceItem(backupSetPath, DeviceType.File);

            restore.Action = RestoreActionType.Database;
            restore.Database = database;
            restore.Devices.Add(destination);
            restore.ReplaceDatabase = true;

            if (verify)
            {
                string errorMessage;

                if (!restore.SqlVerify(server, out errorMessage))
                {
                    throw new Exception(errorMessage);
                }
            }

            restore.SqlRestore(server);
        }
        catch
        {
            throw;
        }
        finally
        {
            //Make Database Multi User
            serverConnection.ExecuteNonQuery(String.Format(_MultiUserCmd, database));
            serverConnection.Disconnect();
        }
    }

    public static void BackupDatabase(string connectionString, string backupSetPath, bool verify)
    {
        SqlConnectionStringBuilder cb = new SqlConnectionStringBuilder(connectionString);
        string database = cb.InitialCatalog;

        cb.InitialCatalog = "master";

        SqlConnection sqlConnection = new SqlConnection(cb.ConnectionString);
        ServerConnection serverConnection = new ServerConnection(sqlConnection);

        try
        {
            //Make Database Single User
            serverConnection.ExecuteNonQuery(String.Format(_SingleUserCmd, database));

            Server server = new Server(serverConnection);
            Backup backup = new Backup();

            BackupDeviceItem destination = new BackupDeviceItem(backupSetPath, DeviceType.File);

            backup.Action = BackupActionType.Database;
            backup.Database = database;
            backup.Devices.Add(destination);
            backup.SqlBackup(server);

            if (verify)
            {
                Restore restore = new Restore();

                restore.Action = RestoreActionType.Database;
                restore.Database = database;
                restore.Devices.Add(destination);
                restore.ReplaceDatabase = true;

                string errorMessage;

                if (!restore.SqlVerify(server, out errorMessage))
                {
                    throw new Exception(errorMessage);
                }
            }
        }
        catch
        {
            throw;
        }
        finally
        {
            //Make Database Multi User
            serverConnection.ExecuteNonQuery(String.Format(_MultiUserCmd, database));
            serverConnection.Disconnect();
        }
    }
}
Другие вопросы по тегам