I am trying to restore a sql server .bak into an empty database using the following c# code:
string dbBakFile = GetBackFileFromZip(restoreConfig.TmpUnZipFolder,restoreConfig.DatabaseFileToRestore);
if (string.IsNullOrEmpty(dbBakFile))
{
response.Status = DatabaseResponseStatus.Error;
response.Message = "No .bak file found in " + restoreConfig.DatabaseToRestore;
return response;
}
var builder =
new SqlConnectionStringBuilder(
ConfigurationManager.ConnectionStrings["myserver"].ConnectionString);
var smoServer =
new Server(new ServerConnection(builder.DataSource,builder.UserID,builder.Password));
var db = smoServer.Databases[restoreConfig.DatabaseToRestore];
if (db != null)
{
smoServer.KillAllProcesses(restoreConfig.DatabaseToRestore);
log.Debug("all processes on db killed");
}
string dbPath = Path.Combine(db.PrimaryFilePath, restoreConfig.DatabaseToRestore + ".mdf");
log.Debug("db path is " +dbPath);
string logPath = Path.Combine(db.PrimaryFilePath,restoreConfig.DatabaseToRestore + "_Log.ldf");
log.Debug("log path is " + logPath);
var restore = new Restore();
var deviceItem =
new BackupDeviceItem(dbBakFile, DeviceType.File);
restore.DatabaseFiles.Add(dbPath);
restore.DatabaseFiles.Add(logPath);
restore.Devices.Add(deviceItem);
restore.Database = restoreConfig.DatabaseToRestore;
restore.FileNumber = 1;
restore.Action = RestoreActionType.Files;
restore.ReplaceDatabase = true;
restore.PercentCompleteNotification = 10;
restore.PercentComplete +=restore_PercentComplete;
restore.Complete += restore_Complete;
restore.SqlRestore(smoServer);
db = smoServer.Databases[restoreConfig.DatabaseToRestore];
db.SetOnline();
smoServer.Refresh();
db.Refresh();
I get the following error:
Microsoft.SqlServer.Management.Smo.FailedOperationException: Restore failed for Server 'IM-M4500\SQLEXPRESS'. ---> Microsoft.SqlServer.Management.Smo.SmoException: System.Data.SqlClient.SqlError: The backup set holds a backup of a database other than the existing 'new-test-44444' database
Yes it does hold different backup and I want to overwrite and replace it also want to move mdf and log files to new files. Am I missing something here in the options of restore?
Many thanks
Ismail
Ok fixed the issue I need to give it the current db logical file name what i was actually doing was giving it the new db logical file name so
//get the logical file names
DataTable dtFileList = restore.ReadFileList(smoServer);
string dbLogicalName = dtFileList.Rows[0][0].ToString();
string logLogicalName = dtFileList.Rows[1][0].ToString();
restore.RelocateFiles.Add(GetRelocateFile(dbLogicalName, dbPath));
restore.RelocateFiles.Add(GetRelocateFile(logLogicalName, logPath));
This works nicely.
Don't create a new database and try to restore on it. Instead use the below query.
RESTORE DATABASE dbname from disk='location' WITH MOVE 'data' TO 'name.mdf' MOVE '_Log' TO 'name_log.ldf'
To Replace the existing database, put its name on the dbname and use WITH REPLACE on the query
Related
I have created a class to backup a database, the code is:
public bool BackupDatabase(string databasename)
{
bool success = false;
try
{
Backup dbBackup = new Backup();
string SqlInstance = #"SERVER\INSTANCE";
string User = ExtractPureUsername(System.Security.Principal.WindowsIdentity.GetCurrent().Name);
string BackupLocation = #"\\SERVER\FOLDER\BACKUPTEST_" + User.ToString() + ".bak";
Server srv = new Server(SqlInstance);
dbBackup.Action = BackupActionType.Database;
dbBackup.Database = databasename;
dbBackup.Devices.AddDevice(BackupLocation, DeviceType.File);
dbBackup.BackupSetName = "Test database backup";
dbBackup.ExpirationDate = DateTime.Today.AddDays(10);
dbBackup.Initialize = false;
dbBackup.PercentComplete += CompletionStatusInPercent;
dbBackup.Complete += Backup_Completed;
dbBackup.SqlBackup(srv);
success = true;
}
catch(Exception ex)
{
Console.WriteLine(ex);
Console.ReadKey();
}
return success;
}
This runs through, and I get the error:
Cannot open backup device - Operating System error 5
If I were to run the backup on the instance referenced, in SSMS, I can backup to the Bakup location that is specified. So I am presuming that the error is occuring becuase the backup is being initiated as the user that is running the C# program, and SQL server is having none of it. Is there a way to specify which user to run the backup as?
You probably have to set the correct file name as local path on the SQL Server machine. So for instance instead of \\ServerName\Whatever, use c:\Whatever. Make sure the file name you generate doesn't contain illegal characters, like \ or something.
I am trying to programmatically create a new database using SMO in C#. For this project, I do not want the .mdf/.ldf files placed in the default folder
"C:\Program Files\Microsoft SQL Server\MSSQL10_50.SQL2008R2\MSSQL\DATA". I have not found anything on the web that tells how to modify the setting for the file location.
I get a failed operation exception when I run the following code:
Server srv = new Server(serverName.Text);
var db = new Database(srv, dbName.Text);
db.Create();
DataFile df = new DataFile(db.FileGroups["PRIMARY"],
dbName.Text, pathText.Text + dbName.Text + "_data.mdf");
df.Create();
LogFile lf = new LogFile(db, "Log01", pathText.Text + dbName.Text + "_log.ldf");
lf.Create();
The exception occurs at the df.Create(); line.
Any ideas?
I think this one answers the question for you.
Use SMO to Change SQL Server Database Default Locations
TTRider's Answer was:
You need to add information about Data and Log files explicitly:
TTRider's answer in the linked question points in the right direction, but is incomplete. Using some additional info from this post I was able to get it working (tested with SMO 2016 libraries).
private void CreateDatabase(string connectionString, string databaseName, string dataFilePath)
{
using (SqlConnection sqlConnection = new SqlConnection(connectionString))
{
ServerConnection serverConnection = new ServerConnection(sqlConnection);
Server sqlServer = new Server(serverConnection);
Database smoDatabase = new Database(sqlServer, databaseName);
string dataFileName = string.Format("{0}_Data", databaseName);
string dataFileFullPath = Path.ChangeExtension(Path.Combine(dataFilePath, dataFileName), ".mdf");
string logFileName = string.Format("{0}_Log", databaseName);
string logFileFullPath = Path.ChangeExtension(Path.Combine(dataFilePath, logFileName), ".ldf");
FileGroup fileGroup = new FileGroup(smoDatabase, "PRIMARY");
smoDatabase.FileGroups.Add(fileGroup);
DataFile dataFile = new DataFile(fileGroup, dataFileName, dataFileFullPath);
dataFile.IsPrimaryFile = true;
fileGroup.Files.Add(dataFile);
LogFile logFile = new LogFile(smoDatabase, logFileName, logFileFullPath);
smoDatabase.LogFiles.Add(logFile);
smoDatabase.Create();
serverConnection.Disconnect();
}
}
I'm trying to create a copy of a table (no data, just the schema) using SQL Server Management Objects (SMO), Transfer class. The only thing I haven't figured out is how to specify what server to copy to, when the servers are on different hosts. In my case, I want to copy from 10.1.2.x to 10.1.2.y. Is there any way to specify this, or does this class not support it?
Perhaps there are better C# solutions?
static void CreateTableFromTable(string fromConnection, string toConnection, string dbName, string tablename, bool copyData = false)
{
Server fromServer = new Server(new ServerConnection(new SqlConnection(fromConnection)));
Database db = fromServer.Databases[dbName];
Transfer transfer = new Transfer(db);
transfer.CopyAllObjects = false;
transfer.DropDestinationObjectsFirst = false;
transfer.CopySchema = false; //Database schema? Or Table schema? I DO NOT want to overwrite the db schema
transfer.CopyData = copyData;
transfer.DestinationServer = "?";
transfer.DestinationDatabase = dbName;
transfer.Options.IncludeIfNotExists = true;
transfer.ObjectList.Add(db.Tables[tablename]);
transfer.TransferData();
}
Have you tried import and export data wizard even importing with table data ,command line or GUI in SQL server 2005/8 and Mysql /MysqlWorkbench.
I'm not sure if you found another solution - or got this one working. If you did not the SMO Scripter object might be worth a look.
This MSDN example could be helpful. You could script the tables and dependencies you want and then open a connection to the destination database and execute the scripts.
static void Main(string[] args)
{
Server sourceServer = new Server("server");
String dbName = "database";
// Connect to the local, default instance of SQL Server.
// Reference the database.
Database db = sourceServer.Databases[dbName];
// Define a Scripter object and set the required scripting options.
Scripter scripter = new Scripter(sourceServer);
scripter.Options.ScriptDrops = false;
scripter.Options.WithDependencies = true;
scripter.Options.Indexes = true; // To include indexes
scripter.Options.DriAllConstraints = true; // to include referential constraints in the script
// Iterate through the tables in database and script each one. Display the script.
foreach (Table tb in db.Tables)
{
// check if the table is not a system table
if (tb.IsSystemObject == false)
{
Console.WriteLine("-- Scripting for table " + tb.Name);
// Generating script for table tb
System.Collections.Specialized.StringCollection sc = scripter.Script(new Urn[] { tb.Urn });
foreach (string st in sc)
{
//ado.net to destination
Console.WriteLine(st);//SqlCommand.ExecuteNonQuery();
}
Console.WriteLine("--");
}
}
}
Did you try to use SELECT ... INTO statement?
For example:
SELECT * INTO DestDatabase.TableName FROM SourceDatabase.TableName
If you don't want to copy data, just add a condition which will be return nothing, ex: WHERE Id = 0
I have make Some Differential Backup for a Database, which will take the Backup for the Last Modified Data which will be appended to the previously happend Full Backup file. Now, when i am trying to take Restore of the .bak file entire Data is getting Backup, is it possible to take the Backup only the Last Backup taken data i wanted? Can, any one help me on this.
private void RestoreDataBase(Server MyServer, Database MyDataBase, string DevicePath, string Type)
{
try
{
progressBar1.Value = 0;
Restore restoreDB = new Restore();
restoreDB.Action = RestoreActionType.Database;
restoreDB.Database = MyDataBase.Name;
restoreDB.Devices.AddDevice(DevicePath, DeviceType.File);
restoreDB.ReplaceDatabase = true;
restoreDB.NoRecovery = true;
restoreDB.PercentComplete += new PercentCompleteEventHandler(rstDatabase_PercentComplete);
restoreDB.Complete += new ServerMessageEventHandler(rstDatabase_Complete);
restoreDB.SqlRestore(MyServer);
}
catch (Exception ex)
{
WriteToListView(ex.Message.ToString());
writetoLog(ex.Message.ToString());
}
}
The above is the coding i am using, and the database is Sql Server 2008, The coding i am using for Differential Backup is as follows
private void BackupDataBaseDifferential(Server MyServer, Database MyDataBase, string DestinationPath, string Type)
{
try
{
WriteToListView("Taking the Differential Backup for " + MyDataBase.Name);
Backup backDB = new Backup();
backDB.Action = BackupActionType.Database;
backDB.Database = MyDataBase.Name;
backDB.Devices.AddDevice(DestinationPath, DeviceType.File);
backDB.BackupSetName = "Sql Database Backup Differential";
backDB.BackupSetDescription = "Sql Database Backup - DifferentialType";
backDB.ExpirationDate = DateTime.Now.AddDays(5);
backDB.Initialize = false;
backDB.Incremental = true;
if (Type == "Manual")
{
progressBar1.Value = 0;
backDB.PercentComplete += new PercentCompleteEventHandler(bd_PercentComplete);
backDB.Complete += new ServerMessageEventHandler(bd_Complete);
}
else if (Type == "Automatic")
{
backDB.PercentComplete += CompletionStatusInPercent;
backDB.Complete += Backup_Completed;
}
backDB.SqlBackup(MyServer);
}
catch (Exception ex)
{
WriteToListView(ex.Message.ToString());
writetoLog(ex.Message.ToString());
}
}
So, if i use the above coding the last data which is modified in the Database (which was already taken Backup Fully previously) will be taken. So, my problem is when i use the RestoreDataBase() method the entire Database is getting restore, bcoz all the Full Backup data and the Differential Backup data will be in only one file ex: Sample.bak. If i want only the last modified data is it not possible to take by Specifying the Date of the Data modified to the Database?
Maybe silly, but if you export your db as .sql, when you need to restore only some data, you can read file and "filter" rows to restore...
Anyway there is another thread talking about this, take a look here.
I am trying to make a copy of a database to a new database on the same server. The server is my local computer running SQL 2008 Express under Windows XP.
Doing this should be quite easy using the SMO.Transfer class and it almost works!
My code is as follows (somewhat simplified):
Server server = new Server("server");
Database sourceDatabase = server.Databases["source database"];
Database newDatbase = new Database(server, "new name");
newDatbase.Create();
Transfer transfer = new Transfer(sourceDatabase);
transfer.CopyAllObjects = true;
transfer.Options.WithDependencies = true;
transfer.DestinationDatabase = newDatbase.Name;
transfer.CopySchema = true;
transfer.CopyData = true;
StringCollection transferScript = transfer.ScriptTransfer();
using (SqlConnection conn = new SqlConnection(connectionString))
{
conn.Open();
using (SqlCommand switchDatabase = new SqlCommand("USE " + newDatbase.Name, conn))
{
switchDatabase.ExecuteNonQuery();
}
foreach (string scriptLine in transferScript)
{
using (SqlCommand scriptCmd = new SqlCommand(scriptLine, conn, transaction))
{
int res = scriptCmd.ExecuteNonQuery();
}
}
}
What I do here is to first create a new database, then generate a copy script using the Transfer class and finally running the script in the new database.
This works fine for copying the structure, but the CopyData option doesn't work!
Are there any undocumented limits to the CopyData option? The documentation only says that the option specifies whether data is copied.
I tried using the TransferData() method to copy the databse without using a script but then I get an exception that says "Failed to connect to server" with an inner exception that says "A network-related or instance-specific error occurred while establishing a connection to SQL Server. The server was not found or was not accessible. Verify that the instance name is correct and that SQL Server is configured to allow remote connections. (provider: Named Pipes Provider, error: 40 - Could not open a connection to SQL Server)"
I also tried to enable Named Pipes on the server, but that doesn't help.
Edit:
I found a solution that works by making a backup and then restoring it to a new database. It's quite clumsy though, and slower than it should be, so I'm still looking for a better solution.
Well, after contacting Microsft Support I got it working properly, but it is slow and more or less useless. Doing a backup and then a restore is much faster and I will be using it as long as the new copy should live on the same server as the original.
The working code is as follows:
ServerConnection conn = new ServerConnection("rune\\sql2008");
Server server = new Server(conn);
Database newdb = new Database(server, "new database");
newdb.Create();
Transfer transfer = new Transfer(server.Databases["source database"]);
transfer.CopyAllObjects = true;
transfer.CopyAllUsers = true;
transfer.Options.WithDependencies = true;
transfer.DestinationDatabase = newdb.Name;
transfer.DestinationServer = server.Name;
transfer.DestinationLoginSecure = true;
transfer.CopySchema = true;
transfer.CopyData = true;
transfer.Options.ContinueScriptingOnError = true;
transfer.TransferData();
The trick was to set the DestinationDatabase property. This must be set even if the target is that same as the source. In addition I had to connect to the server as a named instance instead of using the other connection options.
Try setting SetDefaultInitFields to true on the Server object.
I had the same issue with the SMO database object running slowly. I guess this is because sql server doesn't like to retrieve entire objects and collections at once, instead lazy loading everything, causing a round-trip for each field, which for an entire database is pretty inefficient.
I had a go at getting this working and have come up with an answer that doesn't use the Transfer class. Here is the Method i used:
public bool CreateScript(string oldDatabase, string newDatabase)
{
SqlConnection conn = new SqlConnection("Data Source=.;Initial Catalog=" + newDatabase + ";User Id=sa;Password=sa;");
try
{
Server sv = new Server();
Database db = sv.Databases[oldDatabase];
Database newDatbase = new Database(sv, newDatabase);
newDatbase.Create();
ScriptingOptions options = new ScriptingOptions();
StringBuilder sb = new StringBuilder();
options.ScriptData = true;
options.ScriptDrops = false;
options.ScriptSchema = true;
options.EnforceScriptingOptions = true;
options.Indexes = true;
options.IncludeHeaders = true;
options.WithDependencies = true;
TableCollection tables = db.Tables;
conn.Open();
foreach (Table mytable in tables)
{
foreach (string line in db.Tables[mytable.Name].EnumScript(options))
{
sb.Append(line + "\r\n");
}
}
string[] splitter = new string[] { "\r\nGO\r\n" };
string[] commandTexts = sb.ToString().Split(splitter, StringSplitOptions.RemoveEmptyEntries);
foreach (string command in commandTexts)
{
SqlCommand comm = new SqlCommand(command, conn);
comm.ExecuteNonQuery();
}
return true;
}
catch (Exception e)
{
System.Diagnostics.Debug.WriteLine("PROGRAM FAILED: " + e.Message);
return false;
}
finally
{
conn.Close();
}
}
Here is my solution:
I have a Database named is Olddatabase
I backup it to E:\databackup\Old.bak
If you want to create a Duplicate Database from Olddatabase in the same server with name NewDatabase
3.1 You can use command in query tool : EXEC OldDatabase.dbo.sp_helpfile;
to determinat path of OldDatabase is stored in case you want to save NewDatabase in the same folder.
or You can save NewDatabase in new Path which you want
use this command in Query tool
RESTORE DATABASE NewDatabase FROM DISK = 'E:\databackup\Old.bak'
WITH MOVE 'OldDatabase' TO 'E:\New path (or the same path)\NewDatabase_Data.mdf',
MOVE 'OldDatabase_log' TO 'E:\New path (or the same path)\NewDatabase_Log.ldf';
Note: you can Use these command obove in c# with : Create a Store procedure in sql which include Above commands. And you can call the store procedure in C #