15

I use SQL Server SMO to restore a .bak to a new database, but failed to work.

sql server is 2012 and smo object version is from the latest sdk version 11.0

file .bak was created using sql management studio 2012, same local pc, on the same coding pc as well.

The error message I get is:

Restore failed for Server 'SERVER'.

What's wrong with my code?

string dbPath = Path.Combine(@"d:\my data", dbName + "_db" + ".mdf");
string logPath = Path.Combine(@"d:\my data", dbName + "_db" + "_Log.ldf");

Restore restore = new Restore();

BackupDeviceItem deviceItem = new BackupDeviceItem("d:\template.BAK", DeviceType.File);
restore.Devices.Add(deviceItem);
restore.Database = dbName + "_db";

RelocateFile relocateDataFile = new RelocateFile("Data", dbPath);
RelocateFile relocateLogFile = new RelocateFile("Log", logPath);

restore.RelocateFiles.Add(relocateDataFile);
restore.RelocateFiles.Add(relocateLogFile);

restore.Action = RestoreActionType.Database;
restore.ReplaceDatabase = true;
restore.SqlRestore(server);

UPDATED: I surrended SMO solutions, and tried

 using (SqlConnection connection = new SqlConnection("Data Source=server;user id=sa;password=xxxxx;"))
        {

            using (SqlCommand command = new SqlCommand(@"RESTORE DATABASE beauty01 FROM DISK = 'd:\template.bak' WITH RECOVERY, MOVE 'beauty1' TO 'D:\MyData\beauty01_Data.mdf', MOVE 'beauty1_log' TO 'd:\Mydata\beauty01_Log.ldf', REPLACE", connection))
            {
                connection.Open();
                // Add the parameters for the SelectCommand.


                command.CommandType = CommandType.Text;
                command.ExecuteNonQuery();
            }

        }  >> work good.

Thanks all.

nam vo
  • 3,271
  • 12
  • 49
  • 76
  • Is there an inner exception? Please check in debug, that'll probably give you the real reason. – Bridge Jan 17 '13 at 10:11
  • Also, are you sure you're not trying to overwrite files that already exist? If you use the same `dbName`, you could have data and log files with the same name - try checking to see if the file exists first, and if it does, don't try creating it again. – Bridge Jan 17 '13 at 10:14
  • Cannot open backup device 'd:\template.BAK'. Operating system error 123(The filename, directory name, or volume label syntax is incorrect.). >> the .bak was created by sql management studio 2012 and smo is the correct version (version 11). – nam vo Jan 17 '13 at 10:18
  • Does `d:\template.BAK` exist, and do you have access to it? Is D a network drive? If so, try moving it to a local disk. – Bridge Jan 17 '13 at 10:26
  • yes, template.bak does exist. it's on my local drive. and i got it restored manually on SSMS just fine. it's strange. – nam vo Jan 17 '13 at 10:31
  • 1
    Remove the `RelocateFile` stuff and it should work just fine ;p (that is if you dont need it) – leppie Jan 17 '13 at 10:32
  • no i need them, to restore to the different db. and even without these lines, still cannot open backup device, Operating system error 123 – nam vo Jan 17 '13 at 10:43
  • @namvo Please post how you resolved it as an answer, and accept it. It'll help people experiencing the same problem find an answer by searching, and it'll stop potential answerers coming here to try and solve your problem when it's already resolved! – Bridge Jan 17 '13 at 11:20

1 Answers1

31

I successfully used SMO to restore the database. I'll share my code. Hope it helps. This solution has one caveat though, it considers that you have only one primary data file. Getting to match up the log and data files is really tricky and something can go wrong in many ways. Anyway try and let me know it this helps.

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.IO;
using System.Text;
using System.Threading;
using Microsoft.SqlServer.Management.Common;
using Microsoft.SqlServer.Management.Smo;
using Microsoft.Win32;

namespace DatabaseUtility
{
    public class BackupRestore
    {
        static Server srv;
        static ServerConnection conn;

        public static void BackupDatabase(string serverName, string databaseName, string filePath)
        {
            conn = new ServerConnection();
            conn.ServerInstance = serverName;
            srv = new Server(conn);

            try
            {
                Backup bkp = new Backup();

                bkp.Action = BackupActionType.Database;
                bkp.Database = databaseName;

                bkp.Devices.AddDevice(filePath, DeviceType.File);
                bkp.Incremental = false;

                bkp.SqlBackup(srv);

                conn.Disconnect();
                conn = null;
                srv = null;
            }

            catch (SmoException ex)
            {
                throw new SmoException(ex.Message, ex.InnerException);
            }
            catch (IOException ex)
            {
                throw new IOException(ex.Message, ex.InnerException);
            }
        }

        public static void RestoreDatabase(string serverName, string databaseName, string filePath)
        {

            conn = new ServerConnection();
            conn.ServerInstance = serverName;
            srv = new Server(conn);

            try
            {
                Restore res = new Restore();

                res.Devices.AddDevice(filePath, DeviceType.File);

                RelocateFile DataFile = new RelocateFile();
                string MDF = res.ReadFileList(srv).Rows[0][1].ToString();
                DataFile.LogicalFileName = res.ReadFileList(srv).Rows[0][0].ToString();
                DataFile.PhysicalFileName = srv.Databases[databaseName].FileGroups[0].Files[0].FileName;

                RelocateFile LogFile = new RelocateFile();
                string LDF = res.ReadFileList(srv).Rows[1][1].ToString();
                LogFile.LogicalFileName = res.ReadFileList(srv).Rows[1][0].ToString();
                LogFile.PhysicalFileName = srv.Databases[databaseName].LogFiles[0].FileName;

                res.RelocateFiles.Add(DataFile);
                res.RelocateFiles.Add(LogFile);

                res.Database = databaseName;
                res.NoRecovery = false;
                res.ReplaceDatabase = true;
                res.SqlRestore(srv);
                conn.Disconnect();
            }
            catch (SmoException ex)
            {
                throw new SmoException(ex.Message, ex.InnerException);
            }
            catch (IOException ex)
            {
                throw new IOException(ex.Message, ex.InnerException);
            }
        }

        public static Server Getdatabases(string serverName)
        {
            conn = new ServerConnection();
            conn.ServerInstance = serverName;

            srv = new Server(conn);
            conn.Disconnect();
            return srv;

        }
    }
}
Soham Dasgupta
  • 5,061
  • 24
  • 79
  • 125
  • This code really helped me, with a few modifications. I needed to restore a DB to a different location and that `RelocateFiles` stuff, complex as it is, worked well. – Jez Jul 10 '13 at 15:43
  • Hi, what's the purpose of the relocating files in the database restore operation? – Rusty Wizard Apr 07 '15 at 06:03
  • @RustyWizard Sometimes the database files are not present in the default location. In that case we need to find the file and use it in the restore command so that there are no errors while restoring. – Soham Dasgupta Apr 07 '15 at 13:19
  • variables MDF & LDF are never used! – Hossein Shahdoost Jul 10 '16 at 09:48
  • 5
    You should never catch exceptions and rethrow the way you show here. Instead just use "throw;" - this way you wont lose stack information – Casper Leon Nielsen Sep 03 '16 at 13:53
  • It does not work for me. When the database is being used by SQL Server, the Restore function will raise an exception. – NoName Jun 27 '17 at 07:45