2016-08-24 21 views
9

To jest mój problem, mam przywrócić funkcję w C# pilotowane przez ten odpowiada:SMO: przywracanie do innej bazy danych, dlaczego db ma wartość zerową?

SMO: restoring to a different DB

Ale gdy program próbuje wykonać ten kod db.SetOnline(); zgłasza wyjątek: Object reference not set to an instance of an object.. Problemem jest ... obiekt db jest pusty. Ale dlaczego obiekt db jest NULL?

To jest moja funkcja:

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); 
    } 
} 
+0

Czy db obiekt zerowy przed 'db = srvr.Databases [baseDatosDestino] ''? Jeśli nie, to obiekt 'srvr.Databases [baseDatosDestino]' musi mieć wartość NULL. –

+0

'srvr.Databases [baseDatosDestino]' ma 2 wywołania w liniach: 32 i 50, ale tylko w linii 50 obiekt "db" ma wartość NULL, dlaczego? ... LUB dlaczego 'srvr.Databases [baseDatosDestino]' ma wartość NULL? –

+0

Myślę, że 'srvr.Databases [baseDatosDestino]' nie powinno być puste –

Odpowiedz

0

Widziałem ten problem podczas przywracania bazy danych za pomocą bazy danych SQL Server przywrócić kreatora. Ma to miejsce, gdy docelowa wersja programu SQL Server jest niższa niż wersja źródłowa programu SQL Server. Więc może będziesz próbował przywrócić kopię zapasową bazy danych z SQL Server 2012 do starszej wersji, takiej jak 2008R2. Dlatego proszę potwierdzić, że wersja Destination jest taka sama lub wyższa niż źródłowa baza danych.

0

Myślę, że proces DB Resore jest asynchroniczny. Tak więc, jeśli spróbujesz uzyskać DB zaraz po przywróceniu, db może być w środkowym stanie przywracania i nie jest dostępny przez SMO. Tak więc powinieneś spróbować czekać/ciągnąć, podczas gdy db zostanie utworzony/resotred w serwerze sql i będzie dostępny przez SMO. Na przykład można dodać kod zamiast db folowing = srvr.Databases [baseDatosDestino]:

while((db = srvr.Databases[baseDatosDestino]) == null) 
{ 
    Thread.Sleep(10); 
}