SMO:恢复到不同的数据库,为啥 db 为空?

Posted

技术标签:

【中文标题】SMO:恢复到不同的数据库,为啥 db 为空?【英文标题】:SMO: restoring to a different DB, why db is null?SMO:恢复到不同的数据库,为什么 db 为空? 【发布时间】:2016-12-31 21:35:05 【问题描述】:

这是我的问题,我在 C# 中有一个由这个答案引导的恢复功能:

SMO: restoring to a different DB

但是当程序试图执行这段代码db.SetOnline();时,它会抛出一个异常:Object reference not set to an instance of an object.。问题是... db 对象为空。但是为什么db对象是NULL呢?

这是我的功能:

public void restaurarBackup(string baseDatosDestino, string rutaBackUp, Server srvr)

    try
    
        if (System.IO.Directory.Exists(DBpath))
        
            // Si el usuario ha elegido el archivo desde el que quiere que la base de datos para ser restaurado
            // Crear una nueva base de datos de la operación de restauración
            Restore rstDatabase = new Restore();

            // Set the backup device from which we want to restore, to a file
            BackupDeviceItem bkpDevice = new BackupDeviceItem(DBpath + rutaBackUp, DeviceType.File);

            // Add the backup device to the restore type
            rstDatabase.Devices.Add(bkpDevice);

            // Set the database that we want to perform the restore on
            rstDatabase.Database = baseDatosDestino;

            DataTable dtFileList = rstDatabase.ReadFileList(srvr);
            string mdf_logicalFileName = dtFileList.Rows[0][0].ToString();
            string mdf_PhysicalFileName = String.Format(@"0\1.mdf", srvr.Information.MasterDBPath, baseDatosDestino);
            string ldf_logicalFileName = dtFileList.Rows[1][0].ToString();
            string ldf_PhysicalFileName = String.Format(@"0\1_log.ldf", srvr.Information.MasterDBPath, baseDatosDestino);

            rstDatabase.RelocateFiles.Add(new RelocateFile(mdf_logicalFileName, mdf_PhysicalFileName));
            rstDatabase.RelocateFiles.Add(new RelocateFile(ldf_logicalFileName, ldf_PhysicalFileName));
            srvr.KillAllProcesses(rstDatabase.Database);
            rstDatabase.Wait();

            Database db = srvr.Databases[rstDatabase.Database];

            if (db != null)
            
                db.DatabaseOptions.UserAccess = DatabaseUserAccess.Single;
                db.Alter(TerminationClause.RollbackTransactionsImmediately);
                srvr.DetachDatabase(rstDatabase.Database, false);
            

            // Set the restore type to a database restore
            rstDatabase.Action = RestoreActionType.Database;

            // If the database already exists, replace it
            rstDatabase.ReplaceDatabase = true;
            rstDatabase.NoRecovery = false;

            // Perform the restore
            rstDatabase.SqlRestore(srvr);
            db = srvr.Databases[baseDatosDestino];
            db.SetOnline(); // In this line the db object is null, why?
            db.DatabaseOptions.UserAccess = DatabaseUserAccess.Multiple;
            srvr.Refresh();
        
        else
        
            _infoError = "Verifique la existencia de la ruta de donde se va a restaurar el Backup!";
        
    
    catch (Exception e)
    
        ManejoExcepcion.RegistrarExcepcion(e, out _infoError);
    

【问题讨论】:

db = srvr.Databases[baseDatosDestino]' 之前的 db 对象是否为空?如果不是,那么您的 srvr.Databases[baseDatosDestino] 对象必须为空。 srvr.Databases[baseDatosDestino] 在第 32 行和第 50 行中有 2 个调用,但只有第 50 行对象“db”为 NULL,为什么? ... 或者为什么 srvr.Databases[baseDatosDestino] 为 NULL? 我认为srvr.Databases[baseDatosDestino]不应该为空 可能是在“baseDatosDestino”索引处找不到数据库。肯定知道的一种方法是调试并单步执行您的代码,看看srvr.Databases[baseDatosDestino] 的值是什么。 我想我已经发现发生了什么......当srvr.DetachDatabase(rstDatabase.Database,false);被执行时,数据库被标记为已删除或其他东西,然后第50行中的db = srvr.Databases[baseDatosDestino]返回NULL,因为它看起来不存在。我评论那条线,一切正常 【参考方案1】:

我认为 DB resore 的过程是异步的。因此,如果您尝试在恢复后立即获取 DB,则 db 可能处于中间恢复状态,并且无法通过 SMO 获得。因此,您应该尝试等待/拉动,而 db 将在 sql server 中创建/重新存储,并且可以通过 SMO 使用。例如,您可以添加以下代码而不是 db = srvr.Databases[baseDatosDestino]:

while( ( db = srvr.Databases[baseDatosDestino] ) == null ) 

    Thread.Sleep(10);

【讨论】:

【参考方案2】:

我在使用 SQL Server 数据库恢复向导恢复数据库时看到了这个问题。当 SQL Server 的目标版本低于 SQL Server 的源版本时,就会出现这种情况。因此,您可能会尝试将数据库备份从 SQL Server 2012 恢复到旧版本,例如 2008R2。所以请确认目标版本与源数据库相同或更高。

【讨论】:

以上是关于SMO:恢复到不同的数据库,为啥 db 为空?的主要内容,如果未能解决你的问题,请参考以下文章

如何在 C# 中使用 SMO 使用 FILE STREAM 备份和恢复数据库

为啥使用mysqlbinlog无法恢复数据

SQL Server:为啥要使用 SMO?

IBM DB2 XML 列更新并恢复为空

使用 SMO 更改逻辑数据库名称

replicate-ignore-db=mysql 为啥无效