Impossible to DETACH database (from c#) - c#

I can ATTACH database and copy all the data from one database to another.But on the end i can't detach it using same code.
var connection = new SQLiteConnection(connection)
connection.Open();
sqlAttachCommand = "ATTACH database '" + fileLoc + "' AS toMerge";
var cmd= new SQLiteCommand(sqlAttachCommand);
cmd.Connection = connection;
cmd.ExecuteNonQuery();
...
sqlAttachCommand = "DETACH database '" + fileLoc + "'";
The exception is:
SQL logic error or missing database no such database: C:\temp\database.db".
This is strange because I did attach for it and I did copy of all the data from this database.

The DETACH DATABASE command takes a schema-name as parameter, not a database file.
So your detach command should be like this:
sqlAttachCommand = "DETACH database toMerge";
as in your ATTACH command you named the thing toMerge.
In the SQL Exception the missing database isn't referring to the fact that SQLite lost that file, it is mere trying to tell that you're using a schema-name that doesn't exist.

Related

Error saving data from textbox to sql server table

I have created a WPF desktop application before and I was able to write up the code to save data from a textbox to a table I created in sql server 2012. I tried to create a WPF Web browser application and the same code was not working to save my data to my sql database. I am now trying to create another WPF desktop application and the same code that worked the last time is not working anymore. Please look at my code and help.
private void savebuyers_Click(object sender, RoutedEventArgs e)
{
string connectionstring = null;
connectionstring = "Data Source=FRANCIS;Initial Catalog=Pam Golding;Integrated Security=SSPI";
SqlConnection con = new SqlConnection(connectionstring);
try
{
string query;
query = "insert into buyers (name,number,email) values ('" + namebuyers.Text + "'," + Convert.ToInt32(numberbuyers) + ",'" + emailbuyers.Text + "')";
SqlCommand command = new SqlCommand(query, con);
message1.Text = "Data Saved Successfully!";
con.Open();
command.ExecuteNonQuery();
con.Close();
}
catch
{
message1.Text = "Error While Saving Data!";
}
}
You have missed the Text property of numberbuyers. So it is unable to cast object of type TextBox to type System.IConvertible.
You can fix it like this:
Convert.ToInt32(numberbuyers.Text)
Also you should always use parameterized queries to avoid Sql Injection.

WPF - How to Backup / Restore LocalDB Programmatically - ClickOnce

I have an application which uses EF and LocalDB as it's database, published by ClickOnce.
it's my first time using LocalDB and I don't know how can i add a feature to my application to Backup/Restore The Database Programmatically.
My App Path Installed by ClickOnce :
C:\Users\Mahdi Rashidi\AppData\Local\Apps\2.0\NOL11TLW.9XG\CZM702AQ.LPP\basu..tion_939730333fb6fcc8_0001.0002_fd707bbb3c97f8d3
and This is the location which Database files Installed :
C:\Users\Mahdi Rashidi\AppData\Local\Apps\2.0\NOL11TLW.9XG\CZM702AQ.LPP\basu...exe_939730333fb6fcc8_0001.0002_none_8c555c3966727e7f
How Should I Backup/Restore the Database?
How Can I Keep Database Safe from ClickOnce further Updates?
Thanks alot :)
This is what I did for backup and restore of my localDb
public void BackupDatabase(string filePath)
{
using (TVend2014Entities dbEntities = new TVend2014Entities(BaseData.ConnectionString))
{
string backupQuery = #"BACKUP DATABASE ""{0}"" TO DISK = N'{1}'";
backupQuery = string.Format(backupQuery, "full databsase file path like C:\tempDb.mdf", filePath);
dbEntities.Database.SqlQuery<object>(backupQuery).ToList().FirstOrDefault();
}
}
public void RestoreDatabase(string filePath)
{
using (TVend2014Entities dbEntities = new TVend2014Entities(BaseData.ConnectionString))
{
string restoreQuery = #"USE [Master];
ALTER DATABASE ""{0}"" SET SINGLE_USER WITH ROLLBACK IMMEDIATE;
RESTORE DATABASE ""{0}"" FROM DISK='{1}' WITH REPLACE;
ALTER DATABASE ""{0}"" SET MULTI_USER;";
restoreQuery = string.Format(restoreQuery, "full db file path", filePath);
var list = dbEntities.Database.SqlQuery<object>(restoreQuery).ToList();
var resut = list.FirstOrDefault();
}
}
Hope this is what you want.
I had a bugger of a time getting my backup/restore to work from code in my application. I'm using LOCALDB and wanted to make sure that regardless of the state of the database or the location of the .mdf file that the backup and restore functions would work. After all - the DBMS should take care of that for you. In the end this is how I got my backup and restore functions to work:
Note: code in VB - save the ";" :)
Backup:
Dim cbdfilename As String = controlPath & "\Backup\Temp\cbdb.bak"
Dim connString As String = (server + ";Initial Catalog=master;Integrated Security=True;")
Dim conn As New SqlConnection(connString)
Dim sql As String
sql = "Backup database #DBNAME " _
& " to Disk = #FILENAME" _
& " with Format"
SqlConnection.ClearAllPools()
'execute backup
Dim dbcmd As New SqlCommand(sql, conn)
dbcmd.Parameters.AddWithValue("#DBNAME", database)
dbcmd.Parameters.AddWithValue("#FILENAME", cbdfilename)
conn.Open()
Try
dbcmd.ExecuteNonQuery()
Catch ex As Exception
MsgBox("Backup DB failed" + ex.ToString)
Finally
conn.Close()
conn.Dispose()
End Try
A key thing to note above is the SqlConnection.ClearAllPools() statement. Even though I was sure that all connections had been properly closed and disposed of in other parts of my app - somehow the DBMS was still showing an open thread.
And now the Restore:
SqlConnection.ClearAllPools()
Dim connString As String = (server + ";Initial Catalog=master;Integrated Security=True;")
Dim conn As New SqlConnection(connString)
Dim sql As String
sql = "Use master;" _
& "Alter Database " & database & " Set Single_User With Rollback Immediate;" _
& "Restore Database " & database & " From Disk = #FILENAME" _
& " With Replace;" _
& "Alter Database " & database & " Set Multi_User;"
'execute restore
Dim dbcmd As New SqlCommand(sql, conn)
dbcmd.Parameters.AddWithValue("#FILENAME", cbdfilename)
conn.Open()
Try
dbcmd.ExecuteNonQuery()
Catch ex As Exception
MsgBox("Restore DB failed" + ex.ToString)
Finally
conn.Close()
conn.Dispose()
End Try
What was really weird in the SQL above is that I initially tried to use #Parms for the database name but the ALTER statements would not accept them. Kept kicking back with exceptions.
The biggest difference between my restore and the one from the earlier solution is that I only use the database name ie. "MyDB_TEST" and not the .mdf file name in my Alter and Restore statements.

Connect to a database not created yet?

How do I create a SQL Compact Edition database? I have tried to figure it out, searched the internet and I cant find it (but then again, how do you search for this?!). Here is my code so far:
checkPasswordsMatch();
SqlCEConnection myconn = new SqlCEConnection();
SqlCeCommand myCommand = new SqlCeCommand(
#"CREATE DATABASE ""pwdb.sdf"" DATABASEPASSWORD '" + textBox1.Text + "'");
myCommand.ExecuteNonQuery();
What do I put on the connection part? I dont understand.
UPDATE: I decided to create a database to incorporate with the application, and simply check if there was a value (admin Password) dedicated to the record Master.
Here is my new code:
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
SqlCeConnection myconn = new SqlCeConnection("Data Source = pwdb.sdf;");
SqlCeCommand checkpass = new SqlCeCommand("SELECT * from PW WHERE Name = Master;",myconn);
try
{
myconn.Open();
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString());
}
if (checkpass.ExecuteNonQuery() != null)
{
Application.Run(new enterMasterPassword());
}
else
Application.Run(new mainPassSet());
The problem is, when i execute this now, i get:
An unhandled exception of type 'System.Data.SqlServerCe.SqlCeException' occurred in System.Data.SqlServerCe.dll
Any ideas anyone??
Try using the SqlCeEngine class. With that class you can create a new database:
using (SqlCeEngine engine = new SqlCeEngine())
{
engine.LocalConnectionString = yourConnectionString;
engine.CreateDatabase();
}
Since you likely only want to create the database once you may not want to do it in your code.
A couple suggestions:
1) if you're using Visual Studio you can open the Server Explorer (Under menu View->Server Explorer) and create it there.
2) Use one of the free SQL managers like linkpad or powershell + sqlcmd (there are others)
3) or... Don't know what data model you are using but EntityFramework with "code first" will create the database for you automatically based on your connection string and how you name your data context. Since you are using the sdf tag, maybe you are using EF...

Dropping SQL Server database through C#

I am using this code to delete a database through C#
Int32 result = 0;
try
{
String Connectionstring = CCMMUtility.CreateConnectionString(false, txt_DbDataSource.Text, "master", "sa", "happytimes", 1000);
SqlConnection con = new SqlConnection();
con.ConnectionString = Connectionstring;
String sqlCommandText = "DROP DATABASE [" + DbName + "]";
if (con.State == ConnectionState.Closed)
{
con.Open();
SqlConnection.ClearPool(con);
con.ChangeDatabase("master");
SqlCommand sqlCommand = new SqlCommand(sqlCommandText, con);
sqlCommand.ExecuteNonQuery();
}
else
{
con.ChangeDatabase("master");
SqlCommand sqlCommand = new SqlCommand(sqlCommandText, con);
sqlCommand.ExecuteNonQuery();
}
con.Close();
con.Dispose();
result = 1;
}
catch (Exception ex)
{
result = 0;
}
return result;
But I get an error
Database currently in use
Can anyone help?
Try this:
String sqlCommandText = #"
ALTER DATABASE " + DbName + #" SET SINGLE_USER WITH ROLLBACK IMMEDIATE;
DROP DATABASE [" + DbName + "]";
Also make sure that your connection string defaults you to the master database, or any other database other than the one you're dropping!
As an aside, you really don't need all of that stuff around your queries. The ConnectionState will always start off Closed, so you don't need to check for that. Likewise, wrapping your connection in a using block eliminates the need to explicitly close or dispose the connection. All you really need to do is:
String Connectionstring = CCMMUtility.CreateConnectionString(false, txt_DbDataSource.Text, "master", "sa", "happytimes", 1000);
using(SqlConnection con = new SqlConnection(Connectionstring)) {
con.Open();
String sqlCommandText = #"
ALTER DATABASE " + DbName + #" SET SINGLE_USER WITH ROLLBACK IMMEDIATE;
DROP DATABASE [" + DbName + "]";
SqlCommand sqlCommand = new SqlCommand(sqlCommandText, con);
sqlCommand.ExecuteNonQuery();
}
result = 1;
Here is how you do it using Entity Framework version 6
System.Data.Entity.Database.Delete(connectionString);
You should take a look at SMO.
These allow you to manage all aspects of SQL Server from code, including deleting of databases.
The database object has a Drop method to delete database.
Create sqlconnection object for different database other than you want to delete.
sqlCommandText = "DROP DATABASE [DBNAME]";
sqlCommand = new SqlCommand(sqlCommandText , sqlconnection);
sqlCommand.ExecuteNonQuery();
In this case i would recommend that you take the database offline first... that will close all connections and etc... heres an article on how to do it: http://blog.sqlauthority.com/2010/04/24/sql-server-t-sql-script-to-take-database-offline-take-database-online/
Microsoft clearly states that A database can be dropped regardless of its state: offline, read-only, suspect, and so on. on this MSDN article (DROP DATABASE (Transact-SQL))
Connection pooling at a guess, use sql server's activity monitor to make sure though.
Pooling keeps connections to the database alive in a cache, then when you create a new one, if there's one in the cache it hands it back instead of instantiating a new one. They hang around for a default time, (2 minutes I think) if they don't get re-used in that time, then they killed off.
So as a first go connect straight to master, instead of using change database, as I suspect change database will simply swap connections in the pool.
Add a check routine for database in use (use a connection to master to do it!). You can force the database to be dropped anyway by first executing
ALTER DATABASE [MyDatabase] SET SINGLE_USER WITH ROLLBACK IMMEDIATE
again from the connection to master!
However everybody else using the db, will no longer like you at all...
Just don't use DB name in connection string.
"Data Source=.\SQLEXPRESS;Integrated Security=True;"
I was having the same troubles as Anshuman...
By my testing of the code in question of Anshuman there have been very simple error:
there have to be SqlConnection.ClearAllPools(); instead of SqlConnection.ClearPool(con);
Like this trouble of
"cannot drop database because is in use..."
disappears.

Copy database offline mode

I have been using SMO for a while for transfering databases. It was pretty easy to handle from c# by using the TransferDatabase task.
For my current project this gets to slow. I have to switch to offline mode, where the database is detached and atached.
What is the least troublesome way to start such a process from c#? I know that there is SSIS, but if possible I would not like to use it. Installing SSIS on my machine is a bit painfull.
Just issue the SQL Server Detach and Attach command from c#
Something like this...
var sourceConnectionString = "Data Source=sourceServer;Initial Catalog=MyDB;Integrated Security=True;";
var destinationConnectionString = "Data Source=destinationServer;Initial Catalog=MyDB;Integrated Security=True;";
var sourceLocalPath = #"C:\MSSQL\DATA\MyDB.mdf";
var destinationLocalPath = #"C:\MSSQL\DATA\MyDB.mdf";
var sourceRemotePath = #"\\ServerNameA\ShareName\MyDB.mdf";
var destinationRemotePath = #"\\ServerNameB\ShareName\MyDB.mdf";
// Make connections
var sourceConnection = new SqlConnection(sourceConnectionString);
sourceConnection.Open();
var destinationConnection = new SqlConnection(destinationConnectionString);
destinationConnection.Open();
// Detach source database
var sourceCommand = new SqlCommand("sp_detach_db MyDB", sourceConnection);
sourceCommand.ExecuteNonQuery();
// Detach destination database
var destinationCommand = new SqlCommand("sp_detach_db MyDB", destinationConnection);
destinationCommand.ExecuteNonQuery();
// Copy database file
File.Copy(sourceRemotePath, destinationRemotePath);
// Re-attach source database
sourceCommand = new SqlCommand("CREATE DATABASE MyDbName ON (FILENAME = '" + sourceLocalPath + "') FOR ATTACH", sourceConnection);
sourceCommand.ExecuteNonQuery();
// Re-attach destination database
destinationCommand = new SqlCommand("CREATE DATABASE MyDbName ON (FILENAME = '" + destinationLocalPath + "') FOR ATTACH", destinationConnection);
destinationCommand.ExecuteNonQuery();
I do this work in my project.
you can use SqlBulkCopy class in C#. this class is very powerful and you can copy all of data with best performance.
this class make a bcp command and run it on your server. this commands are like this:
bcp pubs.dbo.authors out c: emppubauthors.bcp –n –Sstevenw –Usa –P
bcp pubs2.dbo.authors in c: emppubauthors.bcp –n –Sstevenw –Usa –P
there is many switches for this command. please see this code:
// Create source connection
SqlConnection source = new SqlConnection(connectionString);
// Create destination connection
SqlConnection destination = new SqlConnection(connectionString);
// Clean up destination table. Your destination database must have the
// table with schema which you are copying data to.
// Before executing this code, you must create a table BulkDataTable
// in your database where you are trying to copy data to.
SqlCommand cmd = new SqlCommand("DELETE FROM BulkDataTable", destination);
// Open source and destination connections.
source.Open();
destination.Open();
cmd.ExecuteNonQuery();
// Select data from Products table
cmd = new SqlCommand("SELECT * FROM Products", source);
// Execute reader
SqlDataReader reader = cmd.ExecuteReader();
// Create SqlBulkCopy
SqlBulkCopy bulkData = new SqlBulkCopy(destination);
// Set destination table name
bulkData.DestinationTableName = "BulkDataTable";
// Write data
bulkData.WriteToServer(reader);
// Close objects
bulkData.Close();
destination.Close();
source.Close();

Categories

Resources