Настройка однопользовательского режима для восстановления резервной копии
У меня есть следующая функция:
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();
}
}
}