I've read a dozen different blogs, as well as reading through the msdn examples and they just aren't working for me.
Ultimately what I'm trying to do is automate moving a DB from our production instance to our dev instance, or the other direction.
The approach I've taken is thus:
- backup/restore to a temp DB
- detach temp DB
- copy mdf and ldf files to the other instance
- reattach.
I'm stuck on 1 and I cannot understand why. Everything I've read claims this should be working.
NOTE: I've set dbName
to the db I want to restore to. I have also set restore.Database = dbName
, where restore
is an instance of the Restore
class in the smo
namespace.
mdf.LogicalFileName = dbName;
mdf.PhysicalFileName = String.Format(@"{0}\{1}.mdf", server.Information.MasterDBPath, dbName);
ldf.LogicalFileName = dbName + "_log";
ldf.PhysicalFileName = String.Format(@"{0}\{1}.ldf", server.Information.MasterDBPath, dbName);
restore.RelocateFiles.Add(mdf);
restore.RelocateFiles.Add(ldf);
restore.SqlRestore(server);
This is the exception I'm getting:
The file 'D:\MSSQL.MIQ_Dev\MSSQL.2\MSSQL\Data\MIQDesign2Detach.mdf' cannot be overwritten. It is being used by database 'MIQDesignTest2'.
File 'MIQDesign' cannot be restored to 'D:\MSSQL.MIQ_Dev\MSSQL.2\MSSQL\Data\MIQDesign2Detach.mdf'. Use WITH MOVE to identify a valid location for the file. The file 'D:\MSSQL.MIQ_Dev\MSSQL.2\MSSQL\Data\MIQDesign2Detach.ldf' cannot be overwritten. It is being used by database 'MIQDesignTest2'. File 'MIQDesign_log' cannot be r开发者_如何转开发estored to 'D:\MSSQL.MIQ_Dev\MSSQL.2\MSSQL\Data\MIQDesign2Detach.ldf'. Use WITH MOVE to identify a valid location for the file. Problems were identified while planning for the RESTORE statement. Previous messages provide details. RESTORE DATABASE is terminating abnormally.
Why is this trying to overwrite the original mdf? Isn't the RelocateFiles
stuff supposed to specify that you want it being saved to a different physical filename?
It is works.
public class DatabaseManager
{
public Action<int, string> OnSqlBackupPercentComplete;
public Action<int, string> OnSqlRestorePercentComplete;
public Action<SqlError> OnSqlBackupComplete;
public Action<SqlError> OnSqlRestoreComplete;
public bool IsConnected { get; private set; }
private ServerConnection _connection;
public void Connect(string userName, string password, string serverName, bool useInteratedLogin)
{
if (useInteratedLogin)
{
var sqlCon = new SqlConnection(string.Format("Data Source={0}; Integrated Security=True; Connection Timeout=5", serverName));
_connection = new ServerConnection(sqlCon);
_connection.Connect();
IsConnected = true;
}
else
{
_connection = new ServerConnection(serverName, userName, password);
_connection.ConnectTimeout = 5000;
_connection.Connect();
IsConnected = true;
}
}
public void BackupDatabase(string databaseName, string destinationPath)
{
var sqlServer = new Server(_connection);
databaseName = databaseName.Replace("[", "").Replace("]", "");
var sqlBackup = new Backup
{
Action = BackupActionType.Database,
BackupSetDescription = "ArchiveDataBase:" + DateTime.Now.ToShortDateString(),
BackupSetName = "Archive",
Database = databaseName
};
var deviceItem = new BackupDeviceItem(destinationPath, DeviceType.File);
sqlBackup.Initialize = true;
sqlBackup.Checksum = true;
sqlBackup.ContinueAfterError = true;
sqlBackup.Devices.Add(deviceItem);
sqlBackup.Incremental = false;
sqlBackup.ExpirationDate = DateTime.Now.AddDays(3);
sqlBackup.LogTruncation = BackupTruncateLogType.Truncate;
sqlBackup.PercentCompleteNotification = 10;
sqlBackup.PercentComplete += (sender, e) => OnSqlBackupPercentComplete(e.Percent, e.Message);
sqlBackup.Complete += (sender, e) => OnSqlBackupComplete(e.Error);
sqlBackup.FormatMedia = false;
sqlBackup.SqlBackup(sqlServer);
}
public DatabaseCollection GetDatabasesList()
{
if (IsConnected)
{
var sqlServer = new Server(_connection);
return sqlServer.Databases;
}
return null;
}
public void RestoreDatabase(string databaseName, string filePath)
{
var sqlServer = new Server(_connection);
databaseName = databaseName.Replace("[", "").Replace("]", "");
var sqlRestore = new Restore();
sqlRestore.PercentCompleteNotification = 10;
sqlRestore.PercentComplete += (sender, e) => OnSqlRestorePercentComplete(e.Percent, e.Message);
sqlRestore.Complete += (sender, e) => OnSqlRestoreComplete(e.Error);
var deviceItem = new BackupDeviceItem(filePath, DeviceType.File);
sqlRestore.Devices.Add(deviceItem);
sqlRestore.Database = databaseName;
DataTable dtFileList = sqlRestore.ReadFileList(sqlServer);
int lastIndexOf = dtFileList.Rows[1][1].ToString().LastIndexOf(@"\");
string physicalName = dtFileList.Rows[1][1].ToString().Substring(0, lastIndexOf + 1);
string dbLogicalName = dtFileList.Rows[0][0].ToString();
string dbPhysicalName = physicalName + databaseName + ".mdf";
string logLogicalName = dtFileList.Rows[1][0].ToString();
string logPhysicalName = physicalName + databaseName + "_log.ldf";
sqlRestore.RelocateFiles.Add(new RelocateFile(dbLogicalName, dbPhysicalName));
sqlRestore.RelocateFiles.Add(new RelocateFile(logLogicalName, logPhysicalName));
sqlServer.KillAllProcesses(sqlRestore.Database);
Database db = sqlServer.Databases[databaseName];
if (db != null)
{
db.DatabaseOptions.UserAccess = DatabaseUserAccess.Single;
db.Alter(TerminationClause.RollbackTransactionsImmediately);
sqlServer.DetachDatabase(sqlRestore.Database, false);
}
sqlRestore.Action = RestoreActionType.Database;
sqlRestore.ReplaceDatabase = true;
sqlRestore.SqlRestore(sqlServer);
db = sqlServer.Databases[databaseName];
db.SetOnline();
sqlServer.Refresh();
db.DatabaseOptions.UserAccess = DatabaseUserAccess.Multiple;
}
public void Disconnect()
{
if (IsConnected)
_connection.Disconnect();
IsConnected = false;
}
}
I ran into a similar problem and I found this solution to be quite helpful.
Take a look - http://www.eggheadcafe.com/software/aspnet/32188436/smorestore-database-name-change.aspx
精彩评论