I'm browsing a .MDF file and uploading its data to a SQL Server database table.
My app has a browse button to select the file and then upload button to perform the bulkcopy operation.
But in second attempt when I choose the .mdf file using OpenFileDialog, it throws an error saying the file is already being used.
private void labelBrowse_Click(object sender, System.EventArgs e)
{
try
{
System.Windows.Forms.OpenFileDialog openFileDialog = new System.Windows.Forms.OpenFileDialog();
openFileDialog.Title = "Select the MDF file to upload";
openFileDialog.Filter = "Data|*.mdf";
if (openFileDialog.ShowDialog() == System.Windows.Forms.DialogResult.OK)
textBoxMdfFilePath.Text = openFileDialog.FileName.ToString();
}
catch (System.Exception ex)
{
System.Windows.Forms.MessageBox.Show(ex.ToString());
}
}
private void labelUpload_Click(object sender, System.EventArgs e)
{
if (string.IsNullOrEmpty(textBoxMdfFilePath.Text.Trim()))
{
System.Windows.Forms.MessageBox.Show("Please select a MDF file to upload");
textBoxMdfFilePath.Text = "";
return;
}
else if (!(System.IO.Path.GetFileName(textBoxMdfFilePath.Text).Equals("Audit.mdf", System.StringComparison.InvariantCultureIgnoreCase)) && !(System.IO.Path.GetFileName(textBoxMdfFilePath.Text).Equals("IPAUDIT.mdf", System.StringComparison.InvariantCultureIgnoreCase)))
{
System.Windows.Forms.MessageBox.Show("Please select the correct MDF file to upload");
textBoxMdfFilePath.Text = "";
return;
}
else
{
uploadToServer(textBoxMdfFilePath.Text);
}
}
void uploadToServer(string path)
{
try
{
string mdfConnectionString = #"data source=172.16.2.136;attachdbfilename=" + path + ";" + "integrated security=true;" + "connect timeout=30;" + "user instance=true";
System.Data.SqlClient.SqlConnection sqlconnection = new System.Data.SqlClient.SqlConnection(mdfConnectionString);
if (System.IO.Path.GetFileName(path).Equals("Audit.mdf", System.StringComparison.InvariantCultureIgnoreCase))
{
System.Data.SqlClient.SqlCommand sqlcommand = new System.Data.SqlClient.SqlCommand("select * from [D-Audit]", sqlconnection);
sqlconnection.Open();
System.Data.DataTable dataTable = new System.Data.DataTable();
dataTable.Load(sqlcommand.ExecuteReader());
sqlconnection.Close();
System.Data.SqlClient.SqlBulkCopy sqlbulkcopy = new System.Data.SqlClient.SqlBulkCopy(System.Configuration.ConfigurationManager.ConnectionStrings["myServerAudit"].ConnectionString);
sqlbulkcopy.DestinationTableName = "[dbo].[D-Audit]";
sqlbulkcopy.BulkCopyTimeout = 1800;
sqlbulkcopy.WriteToServer(dataTable);
sqlbulkcopy.Close();
System.Windows.Forms.MessageBox.Show("Data Uploaded Successfully");
textBoxMdfFilePath.Text = "";
}
else if (System.IO.Path.GetFileName(path).Equals("IPAudit.mdf", System.StringComparison.InvariantCultureIgnoreCase))
{
System.Data.SqlClient.SqlCommand sqlcommand = new System.Data.SqlClient.SqlCommand("select * from IpTransaction", sqlconnection);
sqlconnection.Open();
System.Data.DataTable dataTable = new System.Data.DataTable();
dataTable.Load(sqlcommand.ExecuteReader());
sqlconnection.Close();
System.Data.SqlClient.SqlBulkCopy sqlbulkcopy = new System.Data.SqlClient.SqlBulkCopy(System.Configuration.ConfigurationManager.ConnectionStrings["myServerIPAudit"].ConnectionString);
sqlbulkcopy.DestinationTableName = "IpTransaction";
sqlbulkcopy.BulkCopyTimeout = 1800;
sqlbulkcopy.WriteToServer(dataTable);
sqlbulkcopy.Close();
System.Windows.Forms.MessageBox.Show("Data Uploaded Successfully");
textBoxMdfFilePath.Text = "";
}
sqlconnection.Close();
}
catch (System.Exception ex)
{
System.Windows.Forms.MessageBox.Show(ex.Message);
}
}
You need to set Pooling=False in your connection string
Whats happening here is SQLBulkcopy is creating its own SQLConnection object with connection string you provided. By default, the Connection Pool is true...so when sqlconnection object is created by SQLBulkCopy, it is added in connection pool and connection persists even after application is closed.This mechanism is to optimize performance but in your case that's what is causing issue...so adding Pooling=false in your connection should solve your problem
ConnectionString = "Data Source=MYSQL;Initial Catalog=MyDatabase;Integrated Security=true;Pooling=false"
Additinal Info
It is good practice to wrap your SQLBulkCopy with Using block as it is of type IDisposable so you need not call close explicitly.
When you say on "second attempt", I'm assuming it works on first click but not on subsequent clicks. If that's the case, then the connection is probably not being released and still holding on to the DB. You may try disposing all IDisposables in your code before leaving the event handler.
Related
Im trying to connect to the database MySql but this error was appeared
FileNotFoundException was unhandled
in the line of adapter.Fill.
FileNotFoundException was unhandled Could not load file or assembly 'Renci.SshNet, Version=2016.1.0.0, Culture=neutral, PublicKeyToken=1cee9f8bde3db106' or one of its dependencies. The system cannot find the file specified
class CONNECT
{
private MySqlConnection connection = new MySqlConnection("Datasource=localhost;Port=3306;Username=root;Password=;Database=Csharp_Hotel_DB");
//create a function to return our connection
public MySqlConnection getConnection()
{
return connection;
}
//create a function to open the connection
public void openConnection()
{
if (connection.State == ConnectionState.Closed)
{
connection.Open();
}
}
//create a function to close the connection
public void closeConnection()
{
if (connection.State == ConnectionState.Open)
{
connection.Close();
}
}
}
private void buttonLogin_Click(object sender, EventArgs e)
{
CONNECT conn = new CONNECT();
DataTable table = new DataTable();
MySqlDataAdapter adapter = new MySqlDataAdapter();
MySqlCommand command = new MySqlCommand();
String query = "SELECT * FROM `users` WHERE `username`=#usn AND `password`=#pass";
command.CommandText = query;
command.Connection = conn.getConnection();
command.Parameters.Add("#usn", MySqlDbType.VarChar).Value = textBoxUsername.Text;
command.Parameters.Add("#pass", MySqlDbType.VarChar).Value = textBoxPassword.Text;
adapter.SelectCommand = command;
adapter.Fill(table); //this line is the FileNotFoundException was unhandled
// if the username and the password exists
if (table.Rows.Count > 0)
{
this.Hide();
MessageBox.Show("YES");
Main_Form mform = new Main_Form();
mform.Show();
}
else
{
if (textBoxUsername.Text.Trim().Equals(""))
{
MessageBox.Show("Enter Your Username to Login", "Empty Username", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
else if (textBoxPassword.Text.Trim().Equals(""))
{
MessageBox.Show("Enter Your Password to Login", "Empty Password", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
else
{
MessageBox.Show("Username and Password Doesn't Exists", "Wrong Data", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
}
It's now working c.
Using the MySQL-connector-net-6.3.5 can fix this error or problem because I'm using .net 4
Thank you for your help.
it seems that you do not handle the exceptions adapter.fill could through.
use:
try{
adapter.Fill(table);
} catch(FileNotFoundException e) {
do stuff with e or your code
}
alternatively check the pathes if they exist before using them.
You are creating a data table without passing a name into the constructor. This means that the table is nameless and so when you try to call Fill on a nameless table you get your file not found exception.
You should pass in the table name
DataTable table = new DataTable("users");
This is a bug in MySQL Connector/NET, bug 96614. It will be fixed in Connector/NET 8.0.18.
Fixed as of the upcoming MySQL Connector/NET 8.0.18 release, and here's the changelog entry:
The Renci.SshNet.dll deployment was problematic for Connector/NET 8.0.17
MSI installations. Some applications, such as Microsoft Excel, were unable
to read MySQL data as a result. This fix removes unnecessary dependencies
on the DLL and also ensures that the MSI installation deploys the correct
Renci.SshNet.dll to the GAC.
A workaround you can use today is switching to MySqlConnector, an alternative OSS ADO.NET library for MySQL, which doesn't have this bug.
Ok - I have finally got my connection string and sql string correct in this WPF form. I kept getting reader exceptions until I finally got the sql string the correct way, so since I am not getting errors now - I am assuming it is correct. Have inserted a breakpoint at IDbCommand and stepped through, and all steps seem to go fine. But the program locks up and does not display any data in the datagrid. Cannot even click on the form once all statements are processed. What have I missed here?
This is a Progress OpenEdge DB - and this is the recommended connection and command from Progress.
private void MonReadButton_Click(object sender, RoutedEventArgs e)
{
var estNum = EstTextBox.Text;
{
string connectString = "DSN=****;uid=**;pwd=*****;host=****;port=****;db=****;";
using (OdbcConnection dbConn = new OdbcConnection(connectString))
{
try
{
dbConn.Open();
}
catch (Exception)
{
MessageBox.Show("connection failed");
}
IDbCommand dbcmd = dbConn.CreateCommand();
string sqlstr = #"SELECT ""Estimate"".""Labor-Cost"" FROM ""GAMS1"".""PUB"".""Estimate"" WHERE ""Estimate"".""Estimate-ID""=" + estNum;
dbcmd.CommandText = sqlstr;
IDataReader reader = dbcmd.ExecuteReader();
while (reader.Read())
{
DataTable dt = new DataTable();
dt.Load(reader);
DataGrid1.ItemsSource = dt.DefaultView;
}
reader.Close();
reader = null;
dbcmd.Dispose();
dbcmd = null;
dbConn.Close();
}
}
}
Currectly I am studying and learning and I just wanted to know some logic of this database connection in C#. I wanted to know why the while loop is used I means if I don't use it, will it affect the program or will the program run fine if I take it out. I just wanted to know is it wise to use it or just take it out from the program. Can someone please help me ?? Thank you
private bool filled;
public DataSet ds = new DataSet();
private void bnt_displaylog_Click(object sender, EventArgs e)
{
try
{
string dbconnection = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=Elevator_Database.accdb;";
string dbcommand = "Select * from Log;";
OleDbConnection conn = new OleDbConnection(dbconnection);
OleDbCommand comm = new OleDbCommand(dbcommand, conn);
OleDbDataAdapter adapter = new OleDbDataAdapter(comm);
conn.Open();
//MessageBox.Show("Connection Open ! ");
**while (filled == false)**
{
adapter.Fill(ds);
filled = true;
}
conn.Close();
}
catch (Exception)
{
MessageBox.Show("Can not open connection ! ");
string message = "Error in connection to datasource";
string caption = "Error";
MessageBoxButtons buttons = MessageBoxButtons.OK;
DialogResult result;
result = MessageBox.Show(message, caption, buttons);
}
database_listbox.Items.Clear();
foreach (DataRow row in ds.Tables[0].Rows)
{
database_listbox.Items.Add(row["Date"] + "\t\t" + row["Time"] + "\t\t" + row["Action"]);
}
}
That's just code that was written in a very unclear manner. The while loop will never loop at all. The loop body will either be executed once, or not at all, depending on the value of filled.
In other words, the code could have been written more clearly as:
conn.Open();
if( ! filled )
{
adapter.Fill(ds);
filled = true;
}
conn.Close();
But even then, the code is doing the wrong thing. Think about the case where filled is true. The code that's actually executed is:
conn.Open();
conn.Close();
and what's the point of doing that?
In any case, what the code actually does, either with while or if, is call adapter.Fill(ds) only the first time through. Given that, we should skip setting up the connection entirely when we don't make that call. And let's refactor the code to make it a bit more clear:
private bool filled = false;
public DataSet ds = new DataSet();
private void bnt_displaylog_Click(object sender, EventArgs e)
{
loadDisplayLog();
database_listbox.Items.Clear();
foreach (DataRow row in ds.Tables[0].Rows)
{
database_listbox.Items.Add(
row["Date"] + "\t\t" + row["Time"] + "\t\t" + row["Action"]
);
}
}
private void loadDisplayLog(object sender, EventArgs e)
{
if( filled ) return;
try
{
string dbconnection = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=Elevator_Database.accdb;";
string dbcommand = "Select * from Log;";
OleDbConnection conn = new OleDbConnection(dbconnection);
OleDbCommand comm = new OleDbCommand(dbcommand, conn);
OleDbDataAdapter adapter = new OleDbDataAdapter(comm);
conn.Open();
adapter.Fill(ds);
conn.Close();
filled = true;
}
catch (Exception)
{
MessageBox.Show("Can not open connection ! ");
string message = "Error in connection to datasource";
string caption = "Error";
MessageBoxButtons buttons = MessageBoxButtons.OK;
DialogResult result;
result = MessageBox.Show(message, caption, buttons);
}
}
There are still some issues with the exception handling in this code - will the connection be closed if adapter.Fill(ds); throws an exception? Oops. But I'll leave the rest as an exercise for the reader...
I have a class that creates a database that saves the mdf file in a specified location. Then it copies tables from an existing database. Then creates stored procedures from an sql file. Then detaches the database created from the start once the process is done. My problem is that my detach method won't work throwing an exception saying that the database is in use. I have disposed my connections properly.
This is in-line with my previous question.
Here is my class:
Event
private void btnFullBackup_Click(object sender, EventArgs e)
{
progressBar.Value = 0;
lblStatus.Text = "Starting full backup...";
CreateDB("FULL");
progressBar.Value = 20;
lblStatus.Text = "Copying tables...";
CopyTables("FULL");
progressBar.Value = 60;
lblStatus.Text = "Creating stored procedures...";
CreateStoredProcedures("FULL");
progressBar.Value = 70;
progressBar.Value = 80;
DetachBackup("FULL");
lblStatus.Text = "Done";
progressBar.Value = 100;
MessageBox.Show("Backup was created successfully", "",
MessageBoxButtons.OK, MessageBoxIcon.Information);
}
Methods used:
void CreateDB(string type)
{
//define and browse location to save mdf
lblStatus.Text = "Creating pysical database...";
FolderBrowserDialog folderBrowserDialog = new FolderBrowserDialog();
folderBrowserDialog.ShowDialog();
lblStatus.Text = "Checking folder permission...";
string selectedFolder = folderBrowserDialog.SelectedPath + "\\";
newBackupLocation = selectedFolder;
//check permission
if (WriteAccessToFolder(selectedFolder) == false)
{
MessageBox.Show("The folder you have chosen does not have write permission", "Monytron",
MessageBoxButtons.OK, MessageBoxIcon.Error);
folderBrowserDialog.ShowDialog();
return;
}
//create DB
lblStatus.Text = "Creating database...";
string connectionString = ConfigurationManager.ConnectionStrings["ConnectionString"].ConnectionString;
var query = GetDbCreationQuery(selectedFolder, type);
using (var conn = new SqlConnection(connectionString))
using (var command = new SqlCommand(query, conn))
{
try
{
conn.Open();
command.ExecuteNonQuery();
folderBrowserDialog.Dispose();
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString());
}
finally
{
if ((conn.State == ConnectionState.Open))
{
conn.Close();
}
}
}
}
void CopyTables(string backupDBName)
{
string connectionString = ConfigurationManager.ConnectionStrings["ConnectionString"].ConnectionString;
var query = CopyQuery(backupDBName + DateTime.Now.ToString("yyyyMMdd"));
using (var conn = new SqlConnection(connectionString))
using (var command = new SqlCommand(query, conn))
{
try
{
conn.Open();
command.ExecuteNonQuery();
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString());
}
finally
{
if ((conn.State == ConnectionState.Open))
{
conn.Close();
}
}
}
}
void CreateStoredProcedures(string type)
{
string connectionString = ConfigurationManager.ConnectionStrings["ConnectionString"].ConnectionString;
using (var conn = new SqlConnection(connectionString + ";database=" + type + DateTime.Now.ToString("yyyyMMdd")))
{
string spLocation = File.ReadAllText("CreateStoredProcedures.sql");
Server server = new Server(new ServerConnection(conn));
try
{
server.ConnectionContext.ExecuteNonQuery(spLocation);
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString());
}
}
}
bool DetachBackup(string backupDBName)
{
string connectionString = ConfigurationManager.ConnectionStrings["ConnectionString"].ConnectionString;
var builder = new SqlConnectionStringBuilder(connectionString);
string serverName = builder.DataSource;
string dbName = builder.InitialCatalog;
try
{
Server smoServer = new Server(serverName);
smoServer.DetachDatabase(backupDBName + DateTime.Now.ToString("yyyyMMdd"), false);
return true;
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString());
return false;
}
}
The Connection to the database is in most cases placed in a pool after using. This way you can re-connect quickly using the same connection string, but on the other hand, I suspect this pool of connections is blocking you from detaching a database.
You can probably do something like this:
Put use master as the last statement in each query against database before you close the connection, or
Modify connection string so it doesn't use pooling (uid=...; pwd=...; pooling=false;)
Hope it helps.
You should first kill connections to the database if you want to keep connection pooling. You can do it setting the database in single user access with rollback_immediate clause before calling the detach method.
Have a look here to use C#:
Is there a way to set the DB as Single User Mode in C#?
Or here to run T-SQL script:
https://serverfault.com/questions/76432/how-can-i-detach-a-database-that-is-in-use
I have developed a windows application with vs2010 and c#. I would like to know a way to backup and restore my local mdf database programmatically. With sdf database I use File Copy but it doesn't seem to work with mdf files.
Can anyone help?
Try in this way:
Go to Sql Management Studio and select the database you want to
backup
Right click and select 'Tasks' -> 'Backup'
Adjust the parameters as you like, but don't confirm the dialog
Press the button SCRIPT and dismiss the dialog
On the query window insert the following text before the backup
command
CREATE PROCEDURE DO_BACKUP
AS
BEGIN
-- HERE GOES THE BACKUP TEXT CREATED BY THE SCRIPT BUTTON
-- FOR EXAMPLE
BACKUP DATABASE [Customers]
TO DISK = N'E:\backups\customers.bak'
WITH NOFORMAT, NOINIT,
NAME = N'Customers - Full Database Backup',
SKIP, NOREWIND, NOUNLOAD, STATS = 10
END
and execute (selecting the correct database) using the exclamation mark button.
Now you have a stored procedure called DO_BACKUP that you can call from your code using the normal ADO.NET objects like SqlConnection and SqlCommand
I struggled a lot with this, and the accepted answer does not do the trick, so here is a solution that worked for me (thanks to dnxit)
it may help someone.
Backup
try
{
var dlg = new System.Windows.Forms.FolderBrowserDialog();
var result = dlg.ShowDialog(this.GetIWin32Window());
if (result.ToString() == "OK")
{
var dbfileName = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "LibraryManger.mdf");
var backupConn = new SqlConnection { ConnectionString = eb.GetConnectionString() };
backupConn.Open();
var backupcomm = backupConn.CreateCommand();
var backupdb = $#"BACKUP DATABASE ""{dbfileName}"" TO DISK='{Path.Combine(dlg.SelectedPath,"LibraryManagement.bak")}'";
var backupcreatecomm = new SqlCommand(backupdb, backupConn);
backupcreatecomm.ExecuteNonQuery();
backupConn.Close();
MessageBox.Show($"Database backup has successfully stored in {Path.Combine(dlg.SelectedPath, "LibraryManagement.bak")}", "Confirmation");
}
}
catch (Exception ex)
{
if(ex.Message.Contains("Operating system error"))
{
MessageBox.Show("Please chose a public folder.", "Error", MessageBoxButton.OK, MessageBoxImage.Error);
}
else
MessageBox.Show(ex.Message, "Error", MessageBoxButton.OK, MessageBoxImage.Error);
}
Restore
You'll have to close existing connection before you restore
try
{
if (eb != null)
{
eb.DisposeConnection();
eb = null;
}
var dlg = new OpenFileDialog();
dlg.InitialDirectory = "C:\\";
dlg.Filter = "Database file (*.bak)|*.bak";
dlg.RestoreDirectory = true;
if (Equals(dlg.ShowDialog(), true))
{
using (var con = new SqlConnection())
{
con.ConnectionString = #"Data Source=(LocalDB)\MSSQLLocalDB;Database=Master;Integrated Security=True;Connect Timeout=30;";
con.Open();
var dbfileName = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "LibraryManger.mdf");
using (var cmd = new SqlCommand())
{
cmd.Connection = con;
cmd.CommandText = $#"RESTORE DATABASE ""{dbfileName}"" FROM DISK='{dlg.FileName}'";
cmd.ExecuteNonQuery();
}
con.Close();
}
MessageBox.Show($"Database backup has successfully restored.", "Confirmation");
eb = new EntityBroker.EntityBroker();
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message, "Error", MessageBoxButton.OK, MessageBoxImage.Error);
}