Restore Sqlserver Database Using C# Showing Error - c#

I am trying to backup and restore sql server 2008r2 database, and i successfully backup my database , But the problem is when i am trying to restore my DB its showing the following error
Restore failed for Server 'XXXX-PC\SQLEXPRESS'
And Another important thing is that , When i Close the DB Connection (From server Explorer [right-click->Close Connection]) its working Normally And Correctly
Below is my Backup And Restore Code
Please help me to fix the problem
public static void BackupDatabase(string backUpFile)
{
ServerConnection con = new ServerConnection(#"XXXX-PC\SQLEXPRESS");
Server server = new Server(con);
Backup source = new Backup();
source.Action = BackupActionType.Database;
source.Database = "testBD";
BackupDeviceItem destination = new BackupDeviceItem(backUpFile, DeviceType.File);
source.Devices.Add(destination);
//source.Devices.AddDevice(#"G:\MyBackUp.bak", DeviceType.File);
source.SqlBackup(server);
con.Disconnect();
}
public static void RestoreDatabase(string backUpFile)
{
ServerConnection con = new ServerConnection(#"XXXX-PC\SQLEXPRESS");
Server server = new Server(con);
Restore destination = new Restore();
destination.Action = RestoreActionType.Database;
destination.Database = "testBD";
BackupDeviceItem source = new BackupDeviceItem(backUpFile, DeviceType.File);
destination.Devices.Add(source);
destination.ReplaceDatabase = true;
con.Disconnect();
server.ConnectionContext.Disconnect();
destination.SqlRestore(server);
}
This is the error :
This is the error message in detail:

My guess is that your restore process can't get exclusive access to the database. The Server SMO object has a KillAllProcesses method that takes a database as an argument and does what it says on the tin.

Related

Restoring SQL database from backup as different user

I am trying to programatically restore an SQL database backup using Microsoft.SqlServer.Management.Smo.
This is my code so far:
Server corp = new Server(SQLServerName);
Restore restore = new Restore();
restore.Database = databaseName;
restore.Action = RestoreActionType.Database;
restore.Devices.AddDevice(LocalBackupFilePath, DeviceType.File);
restore.PercentCompleteNotification = 5;
restore.ReplaceDatabase = true;
restore.PercentComplete += DatabaseRestorePercentComplete;
restore.Complete += DatabaseRestoreComplete;
DataTable dbFiles = restore.ReadFileList(corp);
string backupLogicalName_MDF = dbFiles.Rows[0][0].ToString();
string backupLogicalName_LDF = dbFiles.Rows[1][0].ToString();
restore.RelocateFiles.Add(new RelocateFile(backupLogicalName_MDF, #"G:\Databases"));
restore.RelocateFiles.Add(new RelocateFile(backupLogicalName_LDF, #"G:\SqlTranslogs"));
restore.SqlRestore(corp);
When I execute this it gives this error:
Microsoft.SqlServer.Management.Smo.FailedOperationException: Restore failed for Server '<server>'. ---> Microsoft.SqlServer.Management.Smo.SmoException: System.Data.SqlClient.SqlError: The operating system returned the error '5(Access is denied.)' while attempting 'RestoreContainer::ValidateTargetForCreation' on 'G:\Databases'.
From what I read, this is because the user the code is running as doesn't have the right permissions. I don't know what user the code is running as, neither how to change it.
Could you, please, advise me if there is a way to solve this without changing the user and if not - how to change it?

How to restore backup form one linked server to another linked server using C# SMO

Want to restore a database backup from linked server A to a database located on linked-server B using C#. prefer to use SMO.
I can restore from my local backup to local machine.
{
conn = new ServerConnection
{
ConnectionString = #"Data Source =
(localdb)\MSSQLLocalDb;Initial Catalog=master;Integrated Security=true",
};
try
{
//Restore Full
srv = new Server(conn);
//lsrv = srv.LinkedServers[#"DEVSQL\ALPHA"]; need to figure out how to restore to linked server instead of local.
//srv.KillAllProcesses("G4TestNew");
var res = new Restore();
res.Database = "G4TestNew";
res.Action = RestoreActionType.Database;
filePath = #"\\CABCSERVER\Database\Temp\Full.bak";
res.Devices.AddDevice(filePath, DeviceType.File);
res.ReplaceDatabase = true;
res.NoRecovery = true;
var dataFile = new RelocateFile("G4Test", #"C:\TBD\G4Test.mdf");
var logFile = new RelocateFile("G4Test_log", #"C:\TBD\G4TestNew.ldf");
res.RelocateFiles.Add(dataFile);
res.RelocateFiles.Add(logFile);
res.SqlRestore(srv);
}
EDIT(Adding more detail):.
In this case the linked servers are accessed via 'sql server authentication' and application does not have access to the credential required to connect directly and can use 'Integrated Security' to connect to localdb only.
In SMO you would not connect to one server and then administer a linked server. Instead connect directly to the target server. eg:
ConnectionString = #"Data Source =
DEVSQL\ALPHA;Initial Catalog=master;Integrated Security=true",
srv = new Server(conn);

Using SMO Restore Class when there are multiple backup points in .bak file

I am attempting to use SMO to write a simple utility to backup/restore databases. This works very well when there is only one point in time in the backup file. However when there is a backup file that has multiple backup points defined (not backup sets) SMO always chooses the earliest, whereas SSMS will always choose the latest.
This leads to an incorrect restore of the data, and I would like to figure out if there is a property that I can set that will force the Restore class to always use the latest backup point.
I have already tried to set the Restore.ToPointInTime but that won't work due to the recovery model of the database being simple.
I have found a MSDN article describing how to choose your restore time, and it includes setting the database to full recovery mode:
http://technet.microsoft.com/en-us/library/ms179451(v=sql.105).aspx
Is this necessary when using SMO, and is there a way to do it using pure SMO (no C# sql commands)? I have used the Restore.ReadBackupHeaders and from that I am able to extract the available backup points in time, but not able to set the one to restore anywhere.
EDIT:
Here is the code I am using, including a recent change which attempts to set the database recovery model via smo:
public void RestoreDatabase(string databaseName, string backupPath)
{
var server = new Server(GetServerConnection());
//If the database doesn't exist, create it so that we have something
//to overwrite.
if (!server.Databases.Contains(databaseName))
{
var database = new Database(server, databaseName);
database.Create();
}
var targetDatabase = server.Databases[databaseName];
targetDatabase.RecoveryModel = RecoveryModel.Full;
targetDatabase.Alter();
Restore restore = new Restore();
var backupDeviceItem = new BackupDeviceItem(backupPath, DeviceType.File);
restore.Devices.Add(backupDeviceItem);
restore.Database = databaseName;
restore.ReplaceDatabase = true;
restore.Action = RestoreActionType.Database;
var fileList = restore.ReadFileList(server);
var dataFile = new RelocateFile();
string mdf = fileList.Rows[0][1].ToString();
dataFile.LogicalFileName = fileList.Rows[0][0].ToString();
dataFile.PhysicalFileName = server.Databases[databaseName].FileGroups[0].Files[0].FileName;
var logFile = new RelocateFile();
string ldf = fileList.Rows[1][1].ToString();
logFile.LogicalFileName = fileList.Rows[1][0].ToString();
logFile.PhysicalFileName = server.Databases[databaseName].LogFiles[0].FileName;
restore.RelocateFiles.Add(dataFile);
restore.RelocateFiles.Add(logFile);
var backupHeaderInfo = GetBackupHeaderInformation(restore, server);
var latestBackupDate = backupHeaderInfo.Max(backupInfo => backupInfo.BackupStartDate);
restore.ToPointInTime = latestBackupDate.ToString();
server.KillAllProcesses(databaseName);
restore.SqlRestore(server);
}
It seems like this should do the trick, however the line
targetDatabase.RecoveryModel = RecoveryModel.Full
does not seem to do anything to change the recovery model, leading me to still get the following exception:
The STOPAT option is not supported for databases that use the SIMPLE recovery model.
RESTORE DATABASE is terminating abnormally.
EDIT 2:
I added the line
targetDatabase.Alter();
and it fixed the not updating problem. However It now restores but leaves the database in restoring mode, so it is unable to be queried.
EDIT 3:
I got the code working by setting the Restore.FileNumber property to be the maximum value of the positions in the BackupHeaders, which seems to do the trick, though I'm still unsure why the backup file has multiple backup headers, but only a single backup set.
The working code is below.
public void RestoreDatabase(string databaseName, string backupPath)
{
var server = new Server(GetServerConnection());
//If the database doesn't exist, create it so that we have something
//to overwrite.
if (!server.Databases.Contains(databaseName))
{
var database = new Database(server, databaseName);
database.Create();
}
var targetDatabase = server.Databases[databaseName];
targetDatabase.RecoveryModel = RecoveryModel.Full;
targetDatabase.Alter();
Restore restore = new Restore();
var backupDeviceItem = new BackupDeviceItem(backupPath, DeviceType.File);
restore.Devices.Add(backupDeviceItem);
restore.Database = databaseName;
restore.ReplaceDatabase = true;
restore.NoRecovery = false;
restore.Action = RestoreActionType.Database;
var fileList = restore.ReadFileList(server);
var dataFile = new RelocateFile();
dataFile.LogicalFileName = fileList.Rows[0][0].ToString();
dataFile.PhysicalFileName = server.Databases[databaseName].FileGroups[0].Files[0].FileName;
var logFile = new RelocateFile();
logFile.LogicalFileName = fileList.Rows[1][0].ToString();
logFile.PhysicalFileName = server.Databases[databaseName].LogFiles[0].FileName;
restore.RelocateFiles.Add(dataFile);
restore.RelocateFiles.Add(logFile);
var backupHeaderInfo = GetBackupHeaderInformation(restore, server);
restore.FileNumber = backupHeaderInfo.Where(backupInfo => backupInfo.BackupType == BackupType.Database).Max(backupInfo => backupInfo.Position);
server.KillAllProcesses(databaseName);
restore.SqlRestore(server);
targetDatabase.SetOnline();
}
Despite your saying that you don't have multiple backup sets, I think you do. From the documentation for the backupset table:
A backup set contains the backup from a single, successful backup operation.
So, if you have "multiple restore points" in a single backup file, you have multiple backup sets. Verify this by querying the dbo.backupset table in msdb
Pedantry aside, I think you're looking for the FileNumber property on the Restore object. This corresponds to the FILE = n backup set option in the T-SQL restore command. In order to get the last one, just pull the last row from your ReadBackupHeaders call.
To test for yourself, go through the motions of performing a restore through SSMS and then, instead of hitting "ok", hit the "Script" button near the top. I suspect that you'll see a FILE = <some number> in there somewhere.

Database restore error in C# [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Exclusive access could not be obtained because the database is in use
I use C#, .net4 and SQL Server 2008 R2 in project and use this code to restore a database:
_comm = new SqlCommand("use master; RESTORE DATABASE [DB1] FROM DISK = #Address WITH RESTRICTED_USER, FILE = 1, NOUNLOAD, REPLACE, STATS = 10; use DB1;", _conn);
_comm.CommandType = System.Data.CommandType.Text;
_comm.Parameters.AddRange(new SqlParameter[]
{
new SqlParameter("#Address", _path)
});
_conn.Open();
_comm.ExecuteNonQuery();
The following error is displayed:
Exclusive access could not be obtained because the database is in use.
RESTORE DATABASE is terminating abnormally.
Changed database context to 'master'.
Changed database context to 'DB1'.
its better to use SMO (cause no need for master) once you are connected to the server you do whatever you want
using Microsoft.SqlServer.Management.Smo;
...
Server myServer = new Server(#".\SQLExpress");
Database mydb = myServer.Databases["DB1"];
if(mydb!=null)
myServer.KillAllProcesses(mydb.Name);//detach
Restore restoreDB = new Restore();
restoreDB.Database = mydb.Name;
restoreDB.Action = RestoreActionType.Database;
restoreDB.Devices.AddDevice(_path, DeviceType.File);
restoreDB.ReplaceDatabase = true;
restoreDB.NoRecovery = false;
restoreDB.SqlRestore(myServer);
BACKUP
Server myServer = new Server(#".\SQLExpress");
Database mydb = myServer.Databases["DB1"];
Backup bkp = new Backup();
bkp.Action = BackupActionType.Database;
bkp.Database = mydb.Name;
bkp.Devices.AddDevice(_path, DeviceType.File);
bkp.BackupSetName = "DB1 backup";//optional
bkp.BackupSetDescription = "mybackup dated " + DateTime.Now.ToString("dd/MM/yyyy HH:mm:ss");//optional
bkp.Initialize = true;
bkp.Incremental = false;
bkp.SqlBackup(myServer);
References :
C:\Program Files (x86)\Microsoft SQL Server\100\SDK\Assemblies\Microsoft.SqlServer.ConnectionInfo.dll
C:\Program Files (x86)\Microsoft SQL Server\100\SDK\Assemblies\Microsoft.SqlServer.Management.Sdk.Sfc.dll
C:\Program Files (x86)\Microsoft SQL Server\100\SDK\Assemblies\Microsoft.SqlServer.Smo.dll
C:\Program Files (x86)\Microsoft SQL Server\100\SDK\Assemblies\Microsoft.SqlServer.SmoExtended.dll
Insert the line below before calling the SqlCommand:
_conn.ChangeDatabase("master");

Backup folder issues

When running the code below, I keep getting "access is denied", but i have full administrative rights on the folder.
{"Cannot open backup device '\\\\networkDrive\backups\\'. Operating system error 5(Access is denied.).\r\nBACKUP DATABASE is terminating abnormally."}
the folder target is #"\networkDrive\backups";
I've also tried #"C:\backups"\ and #"C:\backups"
private static string publicConString = "server=myServer;Trusted_Connection=Yes;persist security info=False;connection timeout=120";
public static void BackupDatabase(String databaseName, String userName, String password, String serverName, String destinationPath)
{
Backup sqlBackup = new Backup();
sqlBackup.Action = BackupActionType.Database;
sqlBackup.BackupSetDescription = "ArchiveDataBase:" +
DateTime.Now.ToShortDateString();
sqlBackup.BackupSetName = "Archive";
sqlBackup.Database = databaseName;
BackupDeviceItem deviceItem = new BackupDeviceItem(destinationPath, DeviceType.File);
SqlConnection sqlCon = new SqlConnection(publicConString);
ServerConnection connection = new ServerConnection(sqlCon);
Server sqlServer = new Server(connection);
Database db = sqlServer.Databases[databaseName];
sqlBackup.Initialize = true;
sqlBackup.Checksum = true;
sqlBackup.ContinueAfterError = true;
sqlBackup.Devices.Add(deviceItem);
sqlBackup.Incremental = false;
sqlBackup.ExpirationDate = DateTime.Now.AddDays(3);
//sqlBackup.LogTruncation = BackupTruncateLogType.Truncate;
sqlBackup.FormatMedia = false;
sqlBackup.SqlBackup(sqlServer);
From your description, I think you would like to back up database to a network share folder, right?
Based on the error message, I think the SQL Server service account doesn’t have sufficient permission on the share folder. Please ensure the SQL Server service account is a domain account and it has sufficient permissions.
Please refer to this info for more information.
You cannot back up databases to a network drive if your account have not sufficient permissions to access the network drive.

Categories

Resources