当.bak文件中有多个备份点时使用SMO Restore Class

时间:2014-08-12 00:01:32

标签: c# sql-server backup restore smo

我正在尝试使用SMO为备份/恢复数据库编写一个简单的实用程序。当备份文件中只有一个时间点时,这非常有效。但是,当存在定义了多个备份点的备份文件(而不是备份集)时,SMO总是选择最早的,而SSMS将始终选择最新的。

这导致数据的恢复不正确,我想弄清楚是否有可以设置的属性会强制Restore类始终使用最新的备份点。

我已经尝试设置Restore.ToPointInTime,但由于数据库的恢复模式很简单,因此无法正常工作。

我找到了一篇描述如何选择恢复时间的MSDN文章,其中包括将数据库设置为完全恢复模式:

http://technet.microsoft.com/en-us/library/ms179451(v=sql.105).aspx

使用SMO时是否有必要,有没有办法使用纯SMO(没有C#sql命令)?我已经使用了Restore.ReadBackupHeaders,我可以及时提取可用的备份点,但无法将其设置为在任何地方恢复。

修改

以下是我正在使用的代码,包括最近尝试通过smo设置数据库恢复模型的更改:

    public void RestoreDatabase(string databaseName, string backupPath)
    {
        var server = new Server(GetServerConnection());

        //If the database doesn't exist, create it so that we have something
        //to overwrite.
        if (!server.Databases.Contains(databaseName))
        {
            var database = new Database(server, databaseName);
            database.Create();
        }

        var targetDatabase = server.Databases[databaseName];
        targetDatabase.RecoveryModel = RecoveryModel.Full;
        targetDatabase.Alter();

        Restore restore = new Restore();

        var backupDeviceItem = new BackupDeviceItem(backupPath, DeviceType.File);
        restore.Devices.Add(backupDeviceItem);
        restore.Database = databaseName;
        restore.ReplaceDatabase = true;
        restore.Action = RestoreActionType.Database;

        var fileList = restore.ReadFileList(server);

        var dataFile = new RelocateFile();
        string mdf = fileList.Rows[0][1].ToString();
        dataFile.LogicalFileName = fileList.Rows[0][0].ToString();
        dataFile.PhysicalFileName = server.Databases[databaseName].FileGroups[0].Files[0].FileName;

        var logFile = new RelocateFile();
        string ldf = fileList.Rows[1][1].ToString();
        logFile.LogicalFileName = fileList.Rows[1][0].ToString();
        logFile.PhysicalFileName = server.Databases[databaseName].LogFiles[0].FileName;

        restore.RelocateFiles.Add(dataFile);
        restore.RelocateFiles.Add(logFile);

        var backupHeaderInfo = GetBackupHeaderInformation(restore, server);
        var latestBackupDate = backupHeaderInfo.Max(backupInfo => backupInfo.BackupStartDate);

        restore.ToPointInTime = latestBackupDate.ToString();

        server.KillAllProcesses(databaseName);

        restore.SqlRestore(server);
    }

看起来这应该可以解决问题,但行

targetDatabase.RecoveryModel = RecoveryModel.Full

似乎没有做任何改变恢复模型的事情,导致我仍然得到以下异常:

  

使用SIMPLE恢复模型的数据库不支持STOPAT选项。   RESTORE DATABASE异常终止。

编辑2:

我添加了

targetDatabase.Alter();

它修复了不更新的问题。但是它现在恢复但使数据库处于恢复模式,因此无法查询。

编辑3:

我通过将Restore.FileNumber属性设置为BackupHeaders中位置的最大值来获得代码,这似乎可以解决问题,但我仍然不确定为什么备份文件有多个备份头,但只有一个备份集。

工作代码如下。

    public void RestoreDatabase(string databaseName, string backupPath)
    {
        var server = new Server(GetServerConnection());

        //If the database doesn't exist, create it so that we have something
        //to overwrite.
        if (!server.Databases.Contains(databaseName))
        {
            var database = new Database(server, databaseName);
            database.Create();
        }

        var targetDatabase = server.Databases[databaseName];
        targetDatabase.RecoveryModel = RecoveryModel.Full;
        targetDatabase.Alter();

        Restore restore = new Restore();

        var backupDeviceItem = new BackupDeviceItem(backupPath, DeviceType.File);
        restore.Devices.Add(backupDeviceItem);
        restore.Database = databaseName;
        restore.ReplaceDatabase = true;
        restore.NoRecovery = false;
        restore.Action = RestoreActionType.Database;

        var fileList = restore.ReadFileList(server);

        var dataFile = new RelocateFile();
        dataFile.LogicalFileName = fileList.Rows[0][0].ToString();
        dataFile.PhysicalFileName = server.Databases[databaseName].FileGroups[0].Files[0].FileName;

        var logFile = new RelocateFile();
        logFile.LogicalFileName = fileList.Rows[1][0].ToString();
        logFile.PhysicalFileName = server.Databases[databaseName].LogFiles[0].FileName;

        restore.RelocateFiles.Add(dataFile);
        restore.RelocateFiles.Add(logFile);

        var backupHeaderInfo = GetBackupHeaderInformation(restore, server);
        restore.FileNumber = backupHeaderInfo.Where(backupInfo => backupInfo.BackupType == BackupType.Database).Max(backupInfo => backupInfo.Position);

        server.KillAllProcesses(databaseName);

        restore.SqlRestore(server);

        targetDatabase.SetOnline();
    }

1 个答案:

答案 0 :(得分:5)

尽管你说你没有多个备份集,但我认为你这样做了。从备份集表的文档:

  

备份集包含来自单个成功备份操作的备份。

因此,如果您在单个备份文件中有“多个还原点”,则您有多个备份集。通过查询msdb

中的dbo.backupset表来验证这一点

除了Pedantry之外,我认为你正在寻找Restore对象上的FileNumber属性。这对应于T-SQL restore命令中的FILE = n备份集选项。为了得到最后一行,只需从ReadBackupHeaders调用中拉出最后一行。

要自己测试,请完成通过SSMS执行恢复的动作,然后点击顶部附近的“脚本”按钮,而不是点击“确定”。我怀疑你会在那里看到FILE = <some number>