使用C#(SMO)还原具有FILESTREAM数据的数据库的最佳方法

使用C#(SMO)还原具有FILESTREAM数据的数据库的最佳方法,c#,.net,sql-server,winforms,C#,.net,Sql Server,Winforms,我正在编写一个简单的C#应用程序,允许用户通过选择数据库的路径并为数据库提供一个新名称来恢复数据库——我的问题是 还原功能仍会查找生成备份的路径,但会失败 数据库备份包含FILESTREAM数据,而且也会失败,因为我似乎无法解释/或重新定位该数据 代码C# 错误## 引发异常: 中的“Microsoft.SqlServer.Management.Smo.FailedOperationException” Microsoft.SqlServer.SmoExtended.dll Microsoft.

我正在编写一个简单的C#应用程序,允许用户通过选择数据库的路径并为数据库提供一个新名称来恢复数据库——我的问题是

  • 还原功能仍会查找生成备份的路径,但会失败
  • 数据库备份包含FILESTREAM数据,而且也会失败,因为我似乎无法解释/或重新定位该数据
  • 代码C#

    错误##

    引发异常: 中的“Microsoft.SqlServer.Management.Smo.FailedOperationException” Microsoft.SqlServer.SmoExtended.dll Microsoft.SqlServer.Management.Smo.FailedOperationException:还原 服务器“SERVERNAME”失败。--> Microsoft.SqlServer.Management.Common.ExecutionFailureException:异常 执行Transact-SQL语句或批处理时发生异常。 --->System.Data.SqlClient.SqlException:逻辑文件“DatabaseDemo_4do6_EM_INDEXGROUP_log”不是数据库的一部分 “NewDatabaseName”。使用RESTORE FILELISTONLY列出逻辑文件 名字。还原数据库正在异常终止。在 Microsoft.SqlServer.Management.Common.ConnectionManager.ExecuteTSql(ExecuteTSqlAction 操作,对象执行对象,数据集填充数据集,布尔值 (例外情况)在 Microsoft.SqlServer.Management.Common.ServerConnection.ExecuteOnQuery(字符串 sqlCommand,ExecutionTypes executionType,布尔重试)--结束 内部异常堆栈跟踪---在 Microsoft.SqlServer.Management.Common.ServerConnection.ExecuteOnQuery(字符串 sqlCommand,ExecutionTypes executionType,布尔重试)位于 Microsoft.SqlServer.Management.Common.ServerConnection.ExecuteOnQuery(StringCollection sqlCommands、ExecutionTypes、executionType、布尔重试)位于 Microsoft.SqlServer.Management.Smo.BackupRestoreBase.ExecuteSql(服务器 服务器,StringCollection查询)位于 Microsoft.SqlServer.Management.Smo.Restore.SqlRestore(服务器srv)
    ---内部异常堆栈跟踪结束---位于Microsoft.SqlServer.Management.Smo.Restore.SqlRestore(服务器srv)的 程序“[14052]OPSAdmin.exe”已退出,代码为-1(0xFFFFFF)

    问题

  • 如何有效地执行此操作并同时考虑filestream数据
  • 我的“重新定位文件”功能有什么问题

  • 谢谢

    您需要定义单独的变量来保存Filestream文件组名称

    String filestreamfgpphysicalpath=dataFilePath+databaseName;
    字符串filestreamglogicalname;
    字符串dbLogicalName;
    字符串logLogicalName;
    
    您需要在datatable中循环以标识filestream logicalName。您可以使用文件类型列来标识它

    DataTable dtFileList=dbRestore.ReadFileList(sqlServer);
    Foreach(dtFileList中的数据行dr)
    {
    开关(dr[“类型”])
    {     
    案例“D”:
    dbLogicalName=dr[“LogicalName”].ToString();
    打破
    案例“L”:
    logLogicalName=dr[“LogicalName”].ToString();
    打破
    案例“S”:
    filestreamglogicalname=dr[“LogicalName”].ToString();
    打破
    }
    }
    
    现在,还要为filestream定义重定位文件

    dbRestore.RelocateFiles.Add(新的RelocateFile(dbLogicalName,dataFileLocation));
    添加(新的重新定位文件(logLogicalName+“_log”,logFileLocation));
    添加(新的重新定位文件(fileStreamFGLogicalName,filestreamfgpphysicalpath));
    

    注意:我在这里只考虑了三个文件:数据、日志和文件流。您可能有多个数据文件。因此,您需要将数据文件名设置为数组,并在重定位文件中相应地移动它们。

    您需要定义单独的变量来保存Filestream文件组名

    String filestreamfgpphysicalpath=dataFilePath+databaseName;
    字符串filestreamglogicalname;
    字符串dbLogicalName;
    字符串logLogicalName;
    
    您需要在datatable中循环以标识filestream logicalName。您可以使用文件类型列来标识它

    DataTable dtFileList=dbRestore.ReadFileList(sqlServer);
    Foreach(dtFileList中的数据行dr)
    {
    开关(dr[“类型”])
    {     
    案例“D”:
    dbLogicalName=dr[“LogicalName”].ToString();
    打破
    案例“L”:
    logLogicalName=dr[“LogicalName”].ToString();
    打破
    案例“S”:
    filestreamglogicalname=dr[“LogicalName”].ToString();
    打破
    }
    }
    
    现在,还要为filestream定义重定位文件

    dbRestore.RelocateFiles.Add(新的RelocateFile(dbLogicalName,dataFileLocation));
    添加(新的重新定位文件(logLogicalName+“_log”,logFileLocation));
    添加(新的重新定位文件(fileStreamFGLogicalName,filestreamfgpphysicalpath));
    

    注意:我在这里只考虑了三个文件:数据、日志和文件流。您可能有多个数据文件。因此,您需要将数据文件名设置为数组,并在重定位文件中相应地移动它们。

    dtFileList中还有更多行吗?@DavidBrowne Microsoft-好的,dtFileList中有更多行,当我重新定位它们时,恢复工作正常,但我的问题是如何动态处理这一点,考虑到某些数据库可能比dtFileList中的其他数据库有更多的行?谢谢您的输入。dtFileList中有更多的行吗?@DavidBrowne Microsoft-好的,是的,dtFileList中有更多的行,当我重新定位它们时,恢复工作正常,但我的问题是如何动态处理这一点,考虑到某些数据库可能比dtFileList中的其他数据库有更多的行?谢谢你的投入。谢谢@venkataraman的投入,这很有效。关于你的回答,我有一个后续问题。我如何动态地处理这个问题?我按照建议更新了代码,它适用于DataTable中只有3个条目的数据库,但当我尝试使用4个条目的不同数据库时
        Restore dbRestore = new Restore();
        BackupDeviceItem deviceItem = new BackupDeviceItem(filePath, DeviceType.File);
        dbRestore.Devices.Add(deviceItem);
        dbRestore.Database = databaseName;
    
        ServerConnection connection = new ServerConnection(serverName, userName, password);
        Server sqlServer = new Server(connection);
    
        Database db = sqlServer.Databases[databaseName];
        dbRestore.Action = RestoreActionType.Database;
        String dataFileLocation = dataFilePath + databaseName + ".mdf";
        String logFileLocation = logFilePath + databaseName + "_Log.ldf";
        db = sqlServer.Databases[databaseName];
        DataTable dtFileList = dbRestore.ReadFileList(sqlServer);
        string dbLogicalName = dtFileList.Rows[0][0].ToString();
        string logLogicalName = dtFileList.Rows[1][0].ToString();
        dbRestore.RelocateFiles.Add(new RelocateFile(dbLogicalName, dataFileLocation));
        dbRestore.RelocateFiles.Add(new RelocateFile(logLogicalName + "_log", logFileLocation));
        dbRestore.ReplaceDatabase = true;
    
        dbRestore.dbRestore(sqlServer);
        db = sqlServer.Databases[databaseName];
        db.SetOnline();
        sqlServer.Refresh();
    }
    catch (Exception ex)
    {
        Console.Write(ex.ToString());
    
        MessageBox.Show(ex.Message, "This is exception for testing");
    }