An exception occurs when restoring database with c# and SMO - c#

I am college student and I have created a backup and restore function for the project. I am successful in creating the backup function using SMO. But I have some issues with restore function. There is an exception(Exception is given in the image)
This is my code to restore,
static string DATABASENAME = "adora";
static string SEVERNAME = "localhost";
static string CONNECTIONSTRING = "Server=" + SEVERNAME +";Database="+ DATABASENAME + ";Trusted_Connection=True;";
public void RestoreDatabase(String filePath, String dataFilePath, String logFilePath)
{
Restore sqlRestore = new Restore();
BackupDeviceItem deviceItem = new BackupDeviceItem(filePath, DeviceType.File);
sqlRestore.Devices.Add(deviceItem);
sqlRestore.Database = DATABASENAMERE;
using (SqlConnection connectionx = new SqlConnection(CONNECTIONSTRINGRE))
{
connectionx.Open();
// Do work here; connection closed on following line.
ServerConnection connection = new ServerConnection(connectionx);
Server sqlServer = new Server(connection);
Database db = sqlServer.Databases[DATABASENAMERE];
sqlRestore.Action = RestoreActionType.Database;
String dataFileLocation = dataFilePath + DATABASENAMERE + ".mdf";
String logFileLocation = logFilePath + DATABASENAMERE + "_Log.ldf";
db = sqlServer.Databases[DATABASENAMERE];
RelocateFile rf = new RelocateFile(DATABASENAMERE, dataFileLocation);
sqlRestore.RelocateFiles.Add(new RelocateFile(DATABASENAMERE, dataFileLocation));
sqlRestore.RelocateFiles.Add(new RelocateFile(DATABASENAMERE + "_log", logFileLocation));
sqlRestore.ReplaceDatabase = true;
//sqlRestore.Complete += new ServerMessageEventHandler(sqlRestore_Complete);
sqlRestore.PercentCompleteNotification = 10;
// sqlRestore.PercentComplete += new PercentCompleteEventHandler(sqlRestore_PercentComplete);
sqlRestore.SqlRestore(sqlServer);
db = sqlServer.Databases[DATABASENAMERE];
db.SetOnline();
sqlServer.Refresh();
}
}

Related

Problem get Script from Database with .net Core 7

I want to get a script from my database, but it gives the following error:
System.NullReferenceException: 'Object reference not set to an instance of an object.'
Microsoft.SqlServer.Management.Smo.TableCollection.this[string].get
returned null.
Code:
public static string DbGetScript(string connectionString, string databaseName, string filePath)
{
try
{
if (File.Exists(filePath))
File.Delete(filePath);
SqlConnection conn = new SqlConnection(connectionString);
ServerConnection serverConn = new ServerConnection(conn);
var server = new Server(serverConn);
var database = server.Databases[databaseName];
ScriptingOptions scriptOptions = new ScriptingOptions
{
FileName = filePath,
ScriptDrops = false,
ScriptData = true,
ScriptSchema = true,
IncludeIfNotExists = true,
ScriptForCreateDrop = true,
Encoding = Encoding.UTF8
};
string tbScr = "";
foreach (Table myTable in database.Tables)
{
database.Tables[myTable.Name].Script(scriptOptions);
// var tableScripts = myTable.Script(scriptOptions);
// foreach (string script in tableScripts)
// tbScr += script + "\n\n";
}
return filePath;
}
catch (Exception ex)
{
return "Error: " + ex.GetOriginalException().Message;
}
}

Error restoring SQL Server backup to a new database

I created a backup of a SQL Server database named mydb. I need to restore it programmatically with a C# code.
The restore must create a new database named mydbnew. I'm doing it using the Microsoft.SqlServer.Management.Smo library.
The code is this:
public void RestoreDatabase()
{
string databaseName = "mydbnew";
string userName = "user";
string password = "password";
string serverName = "(local)\\SQLEXPRESS";
string sourcePath = #"c:\temp\";
string fileName = $"mydbbackup.bak";
ServerConnection connection = new(serverName, userName, password);
Server sqlServer = new Server(connection);
BackupDeviceItem deviceItem = new(sourcePath + fileName, DeviceType.File);
Restore restore = new Restore();
restore.Database = databaseName;
restore.ReplaceDatabase = true;
restore.NoRecovery = false;
restore.Devices.Add(deviceItem);
RelocateFile dataFile = new RelocateFile();
dataFile.LogicalFileName = databaseName + "_data";
dataFile.PhysicalFileName = databaseName + ".mdf";
RelocateFile logFile = new RelocateFile();
logFile.LogicalFileName = databaseName + "_log";
logFile.PhysicalFileName = databaseName + ".ldf";
restore.RelocateFiles.Add(dataFile);
restore.RelocateFiles.Add(logFile);
restore.SqlRestore(sqlServer);
restore.Devices.Remove(deviceItem);
}
I get an error at restore.SqlRestore(sqlServer):
Logical file 'mydbnew_log' is not part of database 'mydbnew'. Use RESTORE FILELISTONLY to list the logical file names.
RESTORE DATABASE is terminating abnormally.
What is wrong in my code?
Looks to be 2 issues, first one:
RelocateFile logFile = new RelocateFile();
dataFile.LogicalFileName = databaseName + "_log";
dataFile.PhysicalFileName = databaseName + ".ldf";
You are creating a object with name logFile, but in the next statement setting values for the old variable.
I expect you want it to be:
RelocateFile logFile = new RelocateFile();
logFile.LogicalFileName = databaseName + "_log";
logFile.PhysicalFileName = databaseName + ".ldf";
The next issue, the LogicalFileName is the actual logical name in the original database. But, the PhysicalFileName is the new name.
So, as example, if your DB is like this,
,
then the code is like this:
RelocateFile dataFile = new RelocateFile();
dataFile.LogicalFileName = "Mine";
dataFile.PhysicalFileName = sourcePath + databaseName + ".mdf";
RelocateFile logFile = new RelocateFile();
logFile.LogicalFileName = "Mine_log";
logFile.PhysicalFileName = sourcePath + databaseName + ".ldf";
The RelocateFile uses the logical name of old (original database), but creates file in the new location mentioned in your PhysicalFileName
The above code creates file with new name.
Good luck.
Solved.
I changed the Relocate section with this version:
RelocateFile dataFile = new RelocateFile();
dataFile.LogicalFileName = "mydb";
dataFile.PhysicalFileName = Path.Combine(#"C:\Program Files\Microsoft SQL Server\MSSQL14.SQLEXPRESS\MSSQL\DATA", "mydbnew.mdf");
RelocateFile logFile = new RelocateFile();
logFile.LogicalFileName = "mydb_log";
logFile.PhysicalFileName = Path.Combine(#"C:\Program Files\Microsoft SQL Server\MSSQL14.SQLEXPRESS\MSSQL\DATA", "mydbnew.ldf");
Of course I must work to get the paths and names dynamically, but it works.

Backup and restore Azure database programmatically with smo

We have a running web application. Everything is hosted on azure.
We have one sql server and two databases: production and test.
Client requested functionality to backup production db and restore it in place of test db. I am using following code:
public static void BackupDatabase(string databaseName, string userName, string password, string serverName, string destinationPath)
{
try
{
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);
ServerConnection connection = new ServerConnection(serverName, userName, password);
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);
}
catch (FailedOperationException ex)
{
throw;
}
catch(ConnectionFailureException ex)
{
throw;
}
catch (Exception ex)
{
throw;
}
}
public static void RestoreDatabase(string databaseName, string filePath, string serverName, string userName, string password, string dataFilePath, string logFilePath)
{
try
{
Restore sqlRestore = new Restore();
BackupDeviceItem deviceItem = new BackupDeviceItem(filePath, DeviceType.File);
sqlRestore.Devices.Add(deviceItem);
sqlRestore.Database = databaseName;
ServerConnection connection = new ServerConnection(serverName, userName, password);
Server sqlServer = new Server(connection);
Database db = sqlServer.Databases[databaseName];
db.Drop();
sqlRestore.Action = RestoreActionType.Database;
string dataFileLocation = dataFilePath + databaseName + ".mdf";
string logFileLocation = logFilePath + databaseName + "_Log.ldf";
db = sqlServer.Databases[databaseName];
RelocateFile rf = new RelocateFile(databaseName, dataFileLocation);
System.Data.DataTable logicalRestoreFiles = sqlRestore.ReadFileList(sqlServer);
sqlRestore.RelocateFiles.Add(new RelocateFile(logicalRestoreFiles.Rows[0][0].ToString(), dataFileLocation));
sqlRestore.RelocateFiles.Add(new RelocateFile(logicalRestoreFiles.Rows[1][0].ToString(), logFileLocation));
sqlRestore.SqlRestore(sqlServer);
db = sqlServer.Databases[databaseName];
db.SetOnline();
sqlServer.Refresh();
}
catch(ExecutionFailureException ex)
{
throw;
}
}
Everything works locally and on all virtual machines. But now we have everything on Azure and I have no idea what backup directory should I set. It must be directory on server to which sqlclient (probably azure sql client) has access. Same thing goes when it comes to provide location during restoring database to test database.
How to get access to directories where backup can be stored and where mdf and log files can be saved?
Kind regards

BackupDevice.PhysicalLocation does not add to specified location

Using C# and SMO, when I create backups they are being copied to the default backup location used by SQL Server (C:\Program Files\Microsoft SQL Server\MSSQL11.SQLEXPRESS\MSSQL\Backup), instead of the physical location that I specify in code:
Database database = Server.Databases[dbName]);
Backup backup = new Backup();
device = new BackupDevice();
device.Parent = Server;
device.Name = dbName + ".bak";
device.BackupDeviceType = BackupDeviceType.Disk;
device.PhysicalLocation = Path.Combine(filePath + device.Name); // doesn't appear to do anything
device.Create();
backup.Action = BackupActionType.Database;
backup.Database = database.Name;
backup.Devices.AddDevice(filePath, DeviceType.File);
backup.SqlBackup(server);
When I run my code, I find that the path that I specified ("C:\backupTest") is empty and the backup has been added to the default backup location.
Anyone know why this is?
try with below code
static void BackupDataBase(string databaseName, string destinationPath)
{
try
{
Server myServer = GetServer();
Backup backup = new Backup();
backup.Action = BackupActionType.Database;
backup.Database = databaseName;
destinationPath = System.IO.Path.Combine(destinationPath, databaseName + ".bak");
backup.Devices.Add(new BackupDeviceItem(destinationPath, DeviceType.File));
backup.Initialize = true;
backup.Checksum = true;
backup.ContinueAfterError = true;
backup.Incremental = false;
backup.LogTruncation = BackupTruncateLogType.Truncate;
backup.SqlBackup(myServer);
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
}
}
private static Server GetServer()
{
ServerConnection conn = new ServerConnection("server", "username", "pw");
Server myServer = new Server(conn);
return myServer;
}
refere this codeproject article for more information.

Backup a database mdf & Entity Framework

I have a database (mdf file) which I'm approaching with the Entity Framework. Is it possible to make a backup of the MDF file.
I tried already but SMO but the problem is because I'm using a mdf file the database name is empty. I've read that it's autogenerated.
Piece of my backup code:
String destinationPath = "C:\\";
Backup sqlBackup = new Backup();
sqlBackup.Action = BackupActionType.Database;
sqlBackup.BackupSetDescription = "ArchiveDataBase:" + DateTime.Now.ToShortDateString();
sqlBackup.BackupSetName = "Archive";
BackupDeviceItem deviceItem = new BackupDeviceItem(destinationPath, DeviceType.File);
ServerConnection connection = new ServerConnection(".\\SQLEXPRESS");
Server sqlServer = new Server(connection);
StringCollection sc = new StringCollection();
sc.Add(Environment.CurrentDirectory + "\\db\\Xmain.mdf"); //Bin directory
sc.Add(Environment.CurrentDirectory + "\\db\\Xmain_log.ldf");
sqlServer.AttachDatabase("Xmain", sc);
Database db = sqlServer.Databases["Xmain"];
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);
I am missing something here and need more context, but I will rant on for a second and see if anything is helpful.
Do you mean actually back up the file, not the data? If so, the easy answer is no. The problem is SQL Server will lock the file when it is attached to the database server (SQL Express in this case). You can detatch and copy and then attach, but the application will be down during that time. This can also be done manually.
If you want to backup the data, I would consider scheduling it within SQL Server rather than programmatic, unless you cannot do it that way. Backup is more of a maintenance function than a part of the program.
As for your database name being empty, that is impossible. In fact, it looks like you are trying to set up a database called XMain.
You must set initial catalog in connection string in app.config:
<add name="SalaryAndBenefitsEntities" connectionString="metadata=res://*/SalaryAndBenefitsModel.csdl|res://*/SalaryAndBenefitsModel.ssdl|res://*/SalaryAndBenefitsModel.msl;provider=System.Data.SqlClient;provider connection string="data source=.\sqlexpress;attachdbfilename=|DataDirectory|SalaryAndBenefits.mdf;Initial Catalog=SalaryAndBenefit;user instance=true;password=ca;integrated security=SSPI;MultipleActiveResultSets=True;App=EntityFramework"" providerName="System.Data.EntityClient" />
For backUp Follow below:
create sql command content
public string BackUpCommand(string databaseName, string fileAddress)
{
string command = #"BACKUP DATABASE " + databaseName + #"
TO DISK = '" + fileAddress + "' WITH FORMAT";
return command;
}
Write Backup Method:
public class ActionResult
{
public bool Result { get; set; }
public string Message { get; set; }
}
public ActionResult BackUpDatabase(string filePath)
{
ActionResult res = new ActionResult { Result = true };
using (SalaryAndBenefitsEntities _context = new SalaryAndBenefitsEntities())
{
string command = "select db_name()";
string databaseName = _context.Database.SqlQuery(typeof(string), command).ToListAsync().Result.FirstOrDefault().ToString();
string backUpQuery = BackUpCommand(databaseName, filePath);
var result = _context.Database.SqlQuery<List<string>>(backUpQuery).ToList();
if (result.Count() > 0)
{
res.Result = false;
result.ForEach(x =>
{
res.Message += x.ToString();
});
}
return res;
}
}
if return true database backup is successful else not
For restore Follow below:
create sql command content
public string RestoreCommand(string databaseName, string fileAddress)
{
string command = #"use [master]
ALTER DATABASE " + databaseName + #"
SET SINGLE_USER
WITH ROLLBACK IMMEDIATE
RESTORE DATABASE " + databaseName + #"
FROM DISK = N'" + fileAddress + "'";
return command;
}
Write Restore Method:
public ActionResult RestoreDatabase(string filePath)
{
ActionResult res = new ActionResult { Result = true };
using (SalaryAndBenefitsEntities _context = new SalaryAndBenefitsEntities())
{
string command = "select db_name()";
string databaseName = _context.Database.SqlQuery(typeof(string), command).ToListAsync().Result.FirstOrDefault().ToString();
string restoreQuery = RestoreCommand(databaseName, filePath);
var result = _context.Database.SqlQuery<List<string>>(restoreQuery).ToList();
if (result.Count() > 0)
{
res.Result = false;
result.ForEach(x =>
{
res.Message += x.ToString();
});
}
return res;
}
}
if return true database restore is successful else not
the filePath Like: C:\Temp\backup.bak
the Directory of filePath (C:\Temp) must created manually before use of this methods

Categories

Resources