使用SMO代码恢复SQL数据库时遇逻辑文件不匹配异常求助
你在使用SMO执行数据库恢复时碰到的这个异常,核心原因很明确——恢复操作里指定的逻辑文件名和备份文件里实际的逻辑文件名对不上,错误提示已经给出了关键指引:
逻辑文件'Test'不属于数据库'Test'。请使用RESTORE FILELISTONLY列出逻辑文件名。RESTORE DATABASE异常终止。
为什么会出现这个问题?
当你调用Restore.SqlRestore()时,如果没有明确指定备份文件中包含的逻辑数据文件和日志文件名称,或者指定的名称和备份里的不一致,SQL Server就找不到对应的文件来完成恢复映射,直接抛出这个错误。通常数据库的逻辑文件名不会和数据库名完全一致,一般会是XXX_Data(数据文件)、XXX_Log(日志文件)这类命名格式。
一步步解决问题
先获取备份文件里的真实逻辑文件名
你可以通过两种方式拿到这个关键信息:- 直接执行T-SQL命令:
执行后返回的结果集中,RESTORE FILELISTONLY FROM DISK = '你的备份文件完整路径.bak'LogicalName列就是备份文件里的逻辑文件名,同时PhysicalName列会显示原数据库的物理文件路径。 - 用SMO代码获取(更贴合你的开发场景):
Server srv = new Server("servername"); Restore restoreHelper = new Restore(); restoreHelper.Devices.AddDevice("你的备份文件完整路径.bak", DeviceType.File); DataTable fileList = restoreHelper.ReadFileList(srv); // 遍历打印所有逻辑文件信息 foreach (DataRow row in fileList.Rows) { string logicalName = row["LogicalName"].ToString(); string originalPhysicalPath = row["PhysicalName"].ToString(); Console.WriteLine($"逻辑文件名:{logicalName},原物理路径:{originalPhysicalPath}"); }
- 直接执行T-SQL命令:
在恢复代码中正确映射逻辑文件
拿到真实的逻辑文件名后,需要在Restore对象中添加RelocateFile项,将备份里的逻辑文件映射到目标服务器的物理路径上,示例代码如下:// 初始化Server和Restore对象 Server srv = new Server("servername"); Restore restore = new Restore(); restore.Database = "Test"; // 目标数据库名称 restore.Devices.AddDevice("你的备份文件完整路径.bak", DeviceType.File); // 替换成你刚获取到的实际逻辑文件名和目标物理路径 RelocateFile dataRelocate = new RelocateFile("Test_Data", "D:\\Data\\Test.mdf"); RelocateFile logRelocate = new RelocateFile("Test_Log", "D:\\Log\\Test.ldf"); // 添加文件映射规则 restore.RelocateFiles.Add(dataRelocate); restore.RelocateFiles.Add(logRelocate); // 执行恢复操作 restore.SqlRestore(srv);
你提供的完整异常信息
异常详情:Server 'servername' 恢复失败。调用位置:Microsoft.SqlServer.Management.Smo.Restore.SqlRestore(Server srv),以及DBBackupService.DBBackupService.RestoreDB()第115行。
内部调用栈:
Microsoft.SqlServer.Management.Common.ExecutionFailureException:执行Transact-SQL语句或批处理时发生异常。
---> System.Data.SqlClient.SqlException:逻辑文件'Test'不属于数据库'Test'。请使用RESTORE FILELISTONLY列出逻辑文件名。RESTORE DATABASE异常终止。
后续调用栈:
at Microsoft.SqlServer.Management.Common.ConnectionManager.ExecuteTSql(ExecuteTSqlAction action, Object execObject, DataSet fillDataSet, Boolean catchException)
at Microsoft.SqlServer.Management.Common.ServerConnection.ExecuteNonQuery(String sqlCommand, ExecutionTypes executionType)
--- 内部异常栈跟踪结束 ---
at Microsoft.SqlServer.Management.Common.ServerConnection.ExecuteNonQuery(String sqlCommand, ExecutionTypes executionType)
at Microsoft.SqlServer.Management.Common.ServerConnection.ExecuteNonQuery(StringCollection sqlCommands, ExecutionTypes executionType)
at Microsoft.SqlServer.Management.Smo.ExecutionManager.ExecuteNonQuery(StringCollection queries)
at Microsoft.SqlServer.Management.Smo.BackupRestoreBase.ExecuteSql(Server server, StringCollection queries)
at Microsoft.SqlServer.Management.Smo.Restore.SqlRestore(Server srv)
内容的提问来源于stack exchange,提问作者Prajapati Dasharath N

