Backup SQLite database using SaveFileDialog? - c#

I am following the guidance provided here:
Sqlite Online Backup Using System.Data.Sqlite
And it's working as I expect, but I'd like to pass the BackupDb.db file into a SaveFileDialog so that user can save the file outside of the applications folder, preferably on an external drive. I just can't figure this out.
This is what I have so far:
private void btn_backup_db_Click(object sender, RoutedEventArgs e)
{
var ofd1 = new Microsoft.Win32.SaveFileDialog();
using (var source = new SQLiteConnection("Data Source=database.db; Version=3;"))
using (var destination = new SQLiteConnection("Data Source=BackupDb.db; Version=3;"))
{
source.Open();
destination.Open();
source.BackupDatabase(destination, "main", "main", -1, null, 0);
//Microsoft.Win32.SaveFileDialog saveFileDialog;
ofd1.ShowDialog();
}
I know I am missing a step, but I'm not sure what step. I have the ofd1 variable defined as opening a SaveFileDialog, and I'm telling it to open with of1.ShowDialog(); but I can't pass "main" or "destination" into the SaveFileDialog because SQLite doesn't have a definition for showing a dialog.
I'm trying to get the path to the file using:
private string MyDirectory()
{
return Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
}
But I'm getting an exception stating that I don't have read access to the directory.
So then, I switched to trying this, but I'm not sure how to use it correctly. It's pointing to the base directory, but can't locate anything in bin\debug:
var dir = AppDomain.CurrentDomain.BaseDirectory;
This ended up being the answer, I included everything from btn_backup_db_Click:
private void btn_backup_db_Click(object sender, RoutedEventArgs e)
{
var ofd1 = new Microsoft.Win32.SaveFileDialog();
ofd1.Filter = "Database Files (*.db)|*.db";
ofd1.FileName = "database";
// customize file dialog properties here
if (ofd1.ShowDialog() == true)
{
var path = Path.GetFullPath(ofd1.FileName);
var destinationCnx = "Data Source=" + path + "; Version=3;";
using (var source = new SQLiteConnection("Data Source=database.db; Version=3;"))
using (var destination = new SQLiteConnection(destinationCnx))
{
source.Open();
destination.Open();
source.BackupDatabase(destination, "main", "main", -1, null, 0);
}
}
else
{
MessageBox.Show("Error");
}
}
Thanks so much everyone!

The SaveFileDialog class is only an utility to let the user to select where he want to save a file (in the form of path).
To summarize, you need to display the file dialog before doing anything with sqlite. When you got the path, you need to build the back connectionstring.
var ofd1 = new SaveFileDialog();
// customize file dialog properties here
if (ofd1.ShowDialog() == true)
{
var path = Path.GetFullPath(ofd1.FileName);
var destinationCnx = "Data Source=" + path + "; Version=3;"
// do sqlite stuff here
}

Related

Microsoft.SqlServer.Management.Common.ServerConnection constructor does not accept SqlConnection, but it should

so the problems is that i receive an error when passing SqlConnection class to ServerConnection class. the error says:
Severity Code Description Project File Line Suppression State
Error CS1503 Argument 1: cannot convert from 'System.Data.SqlClient.SqlConnection' to 'Microsoft.SqlServer.Management.Common.IRenewableToken'
but here it says it can, and in the visual studio says it has that overload but it wont accept it and wont build the project.
I should also mention that when i try to assign the object directly, Visual Studio gets unresponsive and its framerate is like 0.5/s.like this:
ServerConnection servConn = new ServerConnection(){SqlConnectionObject = conn};
this is the whole code block:
SaveFileDialog sfd = new SaveFileDialog();
string stringCon = #"DefaultConnection";
sfd.Filter = "Database backup files (*.bak)|*.bak";
sfd.Title = "Create Database Backup";
sfd.FileName = DateTime.Today.ToString("ddMMMyyyy") + ".bak";
if (sfd.ShowDialog() == true)
{
SqlConnectionInfo conn = new SqlConnectionInfo(stringCon);
ServerConnection servConn = new ServerConnection();
SqlConnection.ClearAllPools();
conn.Open();
servConn.Connect();
try
{
Server serverdb = new Server(servConn);
Backup backupdb = new Backup() { Action = BackupActionType.Database, Database = "whdb" };
backupdb.Devices.AddDevice(sfd.FileName, DeviceType.File);
backupdb.Initialize = true;
backupdb.Incremental = false;
backupdb.SqlBackupAsync(serverdb);
conn.Close();
Storyboard sb = Resources["sbHideAnimation"] as Storyboard;
StatusLable.Content = #"اطلاعات صادر شد.";
sb.Begin(StatusLable);
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString());
}
There are two different sets of classes for SqlClient.
There are two components
System.Data.SqlClient
Microsoft.Data.SqlClient
So you have to make sure to use the correct using statement.

Using MySqlBulkLoader to upload a DataSet content : Issue with the filename

I'd like to try the performance of MySqlBulkLoader knowing that the Adapter.update() method i'm using is taking roughly 30 mn to run.
I understand you have to go through a file to do it so here is my code :
private void button14_Click(object sender, EventArgs e)
{
string fileName = #"C:\Users\Utilisateur\ds.txt";
if (File.Exists(fileName))
{
File.Delete(fileName);
}
using (StreamWriter sw = File.CreateText(fileName))
{
foreach (DataRow row in Globals.ds.Tables[0].Rows)
{
foreach (object item in row.ItemArray)
{
string itemstr = item.ToString();
sw.Write((string)itemstr + "\t");
}
sw.WriteLine();
}
}
using (var conn = new MySqlConnection(Globals.connString))
{
conn.Open();
MySqlCommand comm = new MySqlCommand("TRUNCATE Song",conn);
comm.ExecuteNonQuery();
var bl = new MySqlBulkLoader(conn)
{
TableName = Globals.ds.Tables[0].ToString(),
Timeout = 600,
FieldTerminator = "\t",
LineTerminator = "\n",
FileName = fileName
};
var numberOfInsertedRows = bl.Load();
Console.WriteLine(numberOfInsertedRows);
}
}
The file is generated ok. but at the var numberOfInsertedRows = bl.Load(); line, i have the following error at run time :
MySql.Data.MySqlClient.MySqlException: 'Can't get stat of '/var/packages/MariaDB10/target/mysql/disk/C:\Users\Utilisateur\ds.txt' (Errcode: 2 "No such file or directory")'
I tried to put "/" instead of "\" in the fileName but it's the same error.
I have no idea what's going on, anyone can help ?
Thanks
By default, MySqlBulkLoader loads a file from the server's file system. To use a local file, set bl.Local = true; before calling bl.Load().
To enable this, you will need to set AllowLoadLocalInfile = True in your connection string; see https://mysqlconnector.net/troubleshooting/load-data-local-infile/
Finally, if you switch to MySqlConnector, you can use its MySqlBulkCopy API to load data directly from a DataTable, instead of first saving it to a local CSV file, then loading that file.

Can't restore a .bak file to a database

I have successfully restored a database using smo restore method. But when I try to restore the same .bak file to another database it returns an exception as seen below
I have created the .bak file from a database template I used which is GC_BranchName. GC_Muntinlupa is the first database I have created and restored the .bak file on to it successfully. Can anyone advise me on this?
Here is my restore code:
bool RestoreDB(string name)
{
try
{
var connection = new ServerConnection(Properties.Settings.Default.Well);
var sqlServer = new Server(connection);
var rstDatabase = new Restore();
rstDatabase.Database = name;
rstDatabase.Action = RestoreActionType.Database;
rstDatabase.Devices.AddDevice(System.Environment.CurrentDirectory + "\\GC.bak", DeviceType.File);
rstDatabase.ReplaceDatabase = true;
rstDatabase.SqlRestore(sqlServer);
connection.Disconnect();
return true;
}
catch (Exception ex)
{
MessageBox.Show("A problem occured when building the branch!" + ex, "Monytron Consolidator", MessageBoxButtons.OK, MessageBoxIcon.Error);
return false;
}
Sorry J.P Masangcay but i didn't had time to put it all together for you until now.
Here is the solution that works for you, verified by me.
Your problem is that you have file conficts if you restore your database backup to a new database.
Why file conflicts?
The default behavior of SQL Server is to restore the database using file paths and names for data and log files as they have been at the time of the backup. Therefore, if that originating database exists at the time of the restore process this leads to filesystem conflicts. They same conflict arises if you restore your database backup template to another server multiple times.
Your Case:
Database: GC_BranchName
Data File: GC_BranchName.mdf
Log File: GC_BranchName_log.ldf
Resore Database: GC_Muntinlupa
Data File: GC_BranchName.mdf
Log File: GC_BranchName_log.ldf
To solve the proplem you have to relocate files to have distinct filenames for your databases. Here is a solution, which simply adds/prepends the "new database name" to all files. This relocating under the hood restores the database using the TSQL "RESTORE DATABASE ... WITH MOVE" option, as your exception above is suggesting.
Resore Database: GC_Muntinlupa
Data File: GC_Muntinlupa_GC_BranchName.mdf
Log File: GC_Muntinlupa_GC_BranchName_log.ldf
bool RestoreDB(string name)
{
try
{
var connection = ServerConnection(Properties.Settings.Default.Well);
var sqlServer = new Server(connection);
var rstDatabase = new Restore();
rstDatabase.Database = name;
rstDatabase.Action = RestoreActionType.Database;
rstDatabase.Devices.AddDevice(System.Environment.CurrentDirectory + "\\GC.bak", DeviceType.File);
rstDatabase.ReplaceDatabase = true;
foreach (DataRow r in rstDatabase.ReadFileList(sqlServer).Rows)
{
var relocateFile = new RelocateFile();
relocateFile.LogicalFileName = r["LogicalName"].ToString();
// move/rename physical filename by prepending database name to prevent FileSystem conflicts
var physicalName = r["PhysicalName"].ToString();
var path = System.IO.Path.GetDirectoryName(physicalName);
var filename = System.IO.Path.GetFileName(physicalName);
physicalName = System.IO.Path.Combine(path, string.Format("{0}_{1}", name, filename));
relocateFile.PhysicalFileName = physicalName;
rstDatabase.RelocateFiles.Add(relocateFile);
}
rstDatabase.SqlRestore(sqlServer);
connection.Disconnect();
return true;
}
catch (Exception ex)
{
MessageBox.Show("A problem occured when building the branch!" + ex, "Monytron Consolidator", MessageBoxButtons.OK, MessageBoxIcon.Error);
return false;
}
}
This should solve the issue
namespace DB_Restore
{
class Program
{
static void Main(string[] args)
{
RestoreDatabase();
}
public static void RestoreDatabase()
{
try
{
ServerConnection connection = new ServerConnection(#"Server\instance", "uname", "PWD");
Server sqlServer = new Server(connection);
Restore rstDatabase = new Restore();
rstDatabase.Action = RestoreActionType.Database;
rstDatabase.Database = "H5MI_Automation_Restore_Backup";
BackupDeviceItem bkpDevice = new BackupDeviceItem(#"E:\DATA\QA_SP\MSSQL11.QA_SP\MSSQL\Backup\H5MI_Automation.bak", DeviceType.File);
rstDatabase.Devices.Add(bkpDevice);
rstDatabase.ReplaceDatabase = true;
//As mentioned in the above solution this code will take care .mdf and .ldf file location issue
foreach (DataRow r in rstDatabase.ReadFileList(sqlServer).Rows)
{
var relocateFile = new RelocateFile();
relocateFile.LogicalFileName = r["LogicalName"].ToString();
Console.WriteLine(relocateFile.LogicalFileName);
var physicalName = r["PhysicalName"].ToString();
Console.WriteLine(physicalName);
var path = System.IO.Path.GetDirectoryName(physicalName);
Console.WriteLine(path);
var filename = System.IO.Path.GetFileName(physicalName);
Console.WriteLine(filename);
physicalName = path + #"\H5MI_Automation_Restore_Backup_" + filename;
Console.WriteLine(physicalName);
relocateFile.PhysicalFileName = physicalName;
Console.WriteLine(relocateFile.PhysicalFileName);
Console.WriteLine(relocateFile);
rstDatabase.RelocateFiles.Add(relocateFile);
}
rstDatabase.SqlRestore(sqlServer);
connection.Disconnect();
}
catch (Exception e)
{
Console.Write(e);
}
}
}
}
Add the explanation of the code. Essentially the issue in the above-attached screenshot is because of the .mdf and .ldf file location. When you try to manually restore the DB u will also face the same issue. attaching the screenshot.Manual DB restore
Why its throwing error?
Its because the file is used by the actual DB(from where .bak file is genrated)
So, this piece of code will help you to change the location of both .mdf and .ldf file path.
foreach (DataRow r in rstDatabase.ReadFileList(sqlServer).Rows)
{
var relocateFile = new RelocateFile();
relocateFile.LogicalFileName = r["LogicalName"].ToString();
Console.WriteLine(relocateFile.LogicalFileName);
var physicalName = r["PhysicalName"].ToString();
Console.WriteLine(physicalName);
var path = System.IO.Path.GetDirectoryName(physicalName);
Console.WriteLine(path);
var filename = System.IO.Path.GetFileName(physicalName);
Console.WriteLine(filename);
physicalName = path + #"\H5MI_Automation_Restore_Backup_" + filename;
Console.WriteLine(physicalName);
relocateFile.PhysicalFileName = physicalName;
Console.WriteLine(relocateFile.PhysicalFileName);
Console.WriteLine(relocateFile);
rstDatabase.RelocateFiles.Add(relocateFile);
}

How to make sure user select specific folder and remove file extension from files in the selected folder?

What I have here is the user select a folder full of .txt files from a external drive and a dummy file is made with the filename to a local folder.
I have 2 questions regarding the code below.
How do I verify that the user select a specific folder?
How do I remove the .txt extension? The code copies the file name and creates the files but its labeled "text.txt.png" but I need it to read "text.png".
int g;
private void folderSelect()
{
FolderBrowserDialog folder = new FolderBrowserDialog();
folder.RootFolder = Environment.SpecialFolder.MyComputer;
folder.ShowNewFolderButton = false;
folder.Description = "Select Folder";
if (folder.ShowDialog() == DialogResult.OK)
{
DirectoryInfo files = new DirectoryInfo(folder.SelectedPath);
FileInfo[] textFiles = files.GetFiles("*.txt");
while (g < textFiles.Length)
{
if (g <= textFiles.Length)
{
File.Create("path/" + (textFiles[g].Name + ".png"));
g++;
}
else
{
break;
}
}
}
Note: I tried using Path.GetFileNameWithoutExtension to remove the extension but Im not sure if i was using it correctly.
Any help would be appreciated. Thank you in advance.
const string NEW_PATH = "path/";
if (!Directory.Exists(NEW_PATH))
Directory.CreateDirectory(NEW_PATH);
const string PATH_TO_CHECK = "correctpath";
FolderBrowserDialog folder = new FolderBrowserDialog();
folder.RootFolder = Environment.SpecialFolder.MyComputer;
folder.ShowNewFolderButton = false;
folder.Description = "Select Folder";
if (folder.ShowDialog() == DialogResult.OK)
{
string pathPastDrive = folder.SelectedPath.Substring(Path.GetPathRoot(folder.SelectedPath).Length).ToLower();
// Here it depends on whether you want to check (1) that the path is EXACTLY what you want,
// or (2) whether the selected path just needs to END in the path that you want.
/*1*/ if (!pathPastDrive == PATH_TO_CHECK)
/*2*/ if (!pathPastDrive.EndsWith(PATH_TO_CHECK))
return; // or you can throw an exception if you want
foreach (string textFile in Directory.GetFiles(folder.SelectedPath, "*.txt"))
File.Create(NEW_PATH + Path.GetFileNameWithoutExtension(textFile) + ".png");
}
You can use GetFileNameWithoutExtension, and it makes it pretty easy.
Also, if you're already sure that your new folder exists, then you can elide the first three lines and replace NEW_PATH with "path/" in the last line.
To see the returned path just use the SelectedPath property, then you can compare it to whatever you had in mind. The # before the path just means I don't have to escape any characters, it's the same as "C:\\MyPath".
FolderBrowserDialog folder = new FolderBrowserDialog();
if (folder.ShowDialog() == DialogResult.OK)
{
if (folder.SelectedPath == #"C:\MyPath")
{
// DO SOMETHING
}
}
You already hit the nail on the head about the file name without extension, change this line:
File.Create("path/" + (textFiles[g].Name + ".png"));
To this:
File.Create("path/" + (Path.GetFileNameWithoutExtension(textFiles[g].Name) + ".png"));
Edit:
To get the folder name you already have the DirectoryInfo object so just use that:
DirectoryInfo files = new DirectoryInfo(folder.SelectedPath);
string folderName = files.Name;

How to give custom made locations for downloading the file

I just wanted to know how can i give a custom made default location for grabbing the files.
I have uploaded a file to the local database and i have binded the file to the gird also. When i press download its showing an error called "the file is not found in location"
If i copy the particular uploaded files to the specified location i can download it easily.
So i just need to know how can i give a default location so that i can upload and downlaod the file from the same exact location.
snapshot of error: https://imageshack.com/i/ewTrmAI2j
Edited the same below code with custom made folder path. But i dont know why the file is always being asked from bin/debug/ folder. WHy its happening like this. IS there any way i can make changes to this folder.. other than bin/debug/ folder
Codes:
private void DownloadAttachment(DataGridViewCell dgvCell)
{
string fileName = Convert.ToString(dgvCell.Value);
//Return if the cell is empty
if (fileName == string.Empty)
return;
FileInfo fileInfo = new FileInfo(fileName);
string fileExtension = fileInfo.Extension;
byte[] byteData = File.ReadAllBytes(fileInfo.FullName); - - - - <<<<< ERROR HERE
//show save as dialog
using (SaveFileDialog saveFileDialog1 = new SaveFileDialog())
{
//Set Save dialog properties
saveFileDialog1.Filter = "Files (*" + fileExtension + ")|*" + fileExtension;
saveFileDialog1.Title = "Save File as";
saveFileDialog1.CheckPathExists = true;
saveFileDialog1.FileName = fileName;
if (saveFileDialog1.ShowDialog() == DialogResult.OK)
{
string s = cncInfoDataGridView.Rows[dgvCell.RowIndex].Cells[1].Value.ToString();
File.WriteAllBytes(saveFileDialog1.FileName, byteData);
byteData = System.Text.Encoding.ASCII.GetBytes(s);
}
}
}
The FileInfo() constructor only works with a full file path. It sounds like you are trying to use the constructor with just a file name, at which point it fails when you try to read the file because its not a valid path. There are a couple possibilities for dealing with this:
Create your own MyFileInfo() class inheriting from FileInfo() and add a constructor that appends your specific path to the filename.
Simply append the path in-line in your code as:
var myPath = #"c:\folder\stuff\";
FileInfo fileInfo = new FileInfo(myPath + fileName);
Normally the path would be setup as a setting in your app.config so you could change it easily if needed.
I found the answer
codes for the binding file path to the gridview and download the file using the file path
private void UploadAttachment(DataGridViewCell dgvCell)
{
using (OpenFileDialog fileDialog = new OpenFileDialog())
{
//Set File dialog properties
fileDialog.CheckFileExists = true;
fileDialog.CheckPathExists = true;
fileDialog.Filter = "All Files|*.*";
fileDialog.Title = "Select a file";
fileDialog.Multiselect = true;
if (fileDialog.ShowDialog() == System.Windows.Forms.DialogResult.OK)
{
string strfilename = fileDialog.FileName;
cncInfoDataGridView.Rows[dgvCell.RowIndex].Cells[1].Value = strfilename;
}
}
}
/// <summary>
/// Download Attachment from the provided DataGridViewCell
/// </summary>
/// <param name="dgvCell"></param>
private void DownloadAttachment(DataGridViewCell dgvCell)
{
string fileName = Convert.ToString(dgvCell.Value);
if (!string.IsNullOrEmpty(fileName))
{
byte[] objData;
FileInfo fileInfo = new FileInfo(fileName);
string fileExtension = fileInfo.Extension;
//show save as dialog
using (SaveFileDialog saveFileDialog1 = new SaveFileDialog())
{
//Set Save dialog properties
saveFileDialog1.Filter = "Files (*" + fileExtension + ")|*" + fileExtension;
saveFileDialog1.Title = "Save File as";
saveFileDialog1.CheckPathExists = true;
saveFileDialog1.FileName = fileName;
if (saveFileDialog1.ShowDialog() == DialogResult.OK)
{
string s = cncInfoDataGridView.Rows[dgvCell.RowIndex].Cells[1].Value.ToString();
objData = File.ReadAllBytes(s);
File.WriteAllBytes(saveFileDialog1.FileName, objData);
}
}
}
}
}

Categories

Resources