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.
Related
I'm just learning databases to store a (large amount) of user entry data.
I have the following code, which checks a record and chooses whether to update or create new
using (SqlConnection connection = new SqlConnection(connectionString))
{
connection.Open();
string sc1 = #"select count(*) from job1 where report = #report";
SqlCommand check = new SqlCommand(sc1, connection);
check.Parameters.AddWithValue("#report", jname);
// check if the report number already exists, if not make a new table otherwise insert
int test = (int)check.ExecuteScalar();
if (test > 0)
{
jobCardExistingTable(connection);
digCardExistingTable(connection);
//insert into existing table code
}
If I use either jobCardExistingTable or digCardExisting table, they work fine. If I use both, I get the error
require open and available connection
I assume that the first ExecuteNonQuery (which are contained in the jobCard and digCard methods) is doing something with the connection - can I keep this one open, or do I have to open a new one each time I call a method? Maybe I'm doing this all wrong anyways...each method is calling a new table in the database, should I be calling them all at once?
Edit: part of the issue is jobCardTable (digCardTable is identical, just a different query)
public void jobCardNewTable(SqlConnection connection)
{
using (connection)
{
string sc3 = "";
sc3 = #"INSERT INTO job1 (" + pv.jobstring + ") VALUES (" + pv.jobparam + ")";
SqlCommand cmd = new SqlCommand(sc3, connection);
queryParams(cmd, 0);
cmd.ExecuteNonQuery();
}
}
Edit: solved - realised that using{} disposes the connection. Took all the using{} out of the methods, and used a single using{} to encompass all the method calls and it works
You should not use using (connection) if you are using same connection in other part of code. using dispose connection and make unavailable for further connection.
So, your jobCardNewTable method implementation should be without using statement :
public void jobCardNewTable(SqlConnection connection)
{
string sc3 = "";
sc3 = #"INSERT INTO job1 (" + pv.jobstring + ") VALUES (" + pv.jobparam + ")";
SqlCommand cmd = new SqlCommand(sc3, connection);
queryParams(cmd, 0);
cmd.ExecuteNonQuery();
}
I would recommend to create new connection whenever you need it and dispose it.
I'm trying to create backup and restore functionality to my Windows form application.
So, I've tried to do a database restore. My code is like this:
string cbdfilename = "c:\\Users\\Public\\Public Document";
SqlConnection.ClearAllPools();
SqlConnection con = new SqlConnection("Data Source=(LocalDB)\\v11.0;AttachDbFilename=|DataDirectory|\\BbCon.mdf;Integrated Security=True;Connect Timeout=30;");
string sql;
sql = "Use master;Alter Database BbCon Set Single_User With Rollback Immediate;Restore Database BbCon From Disk = #FILENAME With Replace;Alter Database BbCon Set Multi_User;";
SqlCommand cmd = new SqlCommand(sql, con);
cmd.Parameters.AddWithValue("#FILENAME", cbdfilename);
con.Open();
try
{
cmd.ExecuteNonQuery();
}
catch(Exception ex)
{
MessageBox.Show("Restore DB failed" + ex.ToString());
}
finally
{
con.Close();
con.Dispose();
}
But when I try to run this, I get an error:
Restore db failed System.Data.SqlClient.SqlException(0X80131904):userdoesnot have permission to alter database BbCon.mdf the database doesnot exist or or datbase is not in a state that allows access checks.
Can anyone help me please?
Are you trying to Backup or Restore? You mention Backup in the Title and the commmand is for Restore.
There're not many example cases for localDB yet.
Utilize my code as below. Hope this helps..
For Backup-
string master_ConnectionString = #"Data Source=(LocalDB)\MSSQLLocalDB;Database=Master;Integrated Security=True;Connect Timeout=30;";
using (SqlConnection masterdbConn = new SqlConnection())
{
masterdbConn.ConnectionString = master_ConnectionString;
masterdbConn.Open();
using (SqlCommand multiuser_rollback_dbcomm = new SqlCommand())
{
multiuser_rollback_dbcomm.Connection = masterdbConn;
multiuser_rollback_dbcomm.CommandText= #"ALTER DATABASE yourdbname SET MULTI_USER WITH ROLLBACK IMMEDIATE";
multiuser_rollback_dbcomm.ExecuteNonQuery();
}
masterdbConn.Close();
}
SqlConnection.ClearAllPools();
using (SqlConnection backupConn = new SqlConnection())
{
backupConn.ConnectionString = yourConnectionString;
backupConn.Open();
using (SqlCommand backupcomm = new SqlCommand())
{
backupcomm.Connection = backupConn;
backupcomm.CommandText= #"BACKUP DATABASE yourdbname TO DISK='c:\yourdbname.bak'";
backupcomm.ExecuteNonQuery();
}
backupConn.Close();
}
For Restore-
string master_ConnectionString = #"Data Source=(LocalDB)\MSSQLLocalDB;Database=Master;Integrated Security=True;Connect Timeout=30;";
using (SqlConnection restoreConn = new SqlConnection())
{
restoreConn.ConnectionString = master_ConnectionString;
restoreConn.Open();
using (SqlCommand restoredb_executioncomm = new SqlCommand())
{
restoredb_executioncomm.Connection = restoreConn;
restoredb_executioncomm.CommandText = #"RESTORE DATABASE yourdbname FROM DISK='c:\yourdbname.bak'";
restoredb_executioncomm.ExecuteNonQuery();
}
restoreConn.Close();
}
Update-
Oops, sorry, my code is for SQL localDB 2014 but it seems you're using 2012.
Kindly replace (LocalDB)\MSSQLLocalDB to (LocalDB)\v11.0
And kindly just try with above change.
And for your information, as per my experience, if I wrote |Data Directory| in my connectionString, I could only read (SQL SELECT command) the Database. In other word to say, the Insert and Update commands could be done but the database was not inserted or updated actually without any exception. I think setting as |Data Directory| would make the database as read-only and I've found some people were having difficulties to insert or update to database with |Data Directory| setting.
Hope your good days ! Thanks !
public TransImport()
{
ConnString = ConfigurationManager.ConnectionStrings["Connection"].ConnectionString;
SqlConnection conn_new;
SqlCommand command_serial_new;
SqlConnection conn;
SqlCommand command_serial;
SqlTransaction InsertUpdateSerialNumbers;
conn = new SqlConnection(ConnString);
command_serial = conn.CreateCommand();
conn_new = new SqlConnection(ConnString);
command_serial_new = conn_new.CreateCommand();
command_serial_new.CommandText = "SELECT 1 FROM YSL00 WHERE SERLNMBR = #slnr";
var p = new SqlParameter("#slnr", SqlDbType.NVarChar, 50);
command_serial_new.Parameters.Add(p);
//Here you will start reading flat file to get serialnumber.
InsertUpdateSerialNumbers = conn.BeginTransaction();
while (!headerFileReader.EndOfStream)
{
headerRow = headerFileReader.ReadLine();
if (CheckSerialNumber(headerFields[0].Trim()))
DisplayMessage("Good serialnumber"); //this function is not copied here.
}
InsertUpdateSerialNumbers.Commit();
}
private Boolean CheckSerialNumber(string SerialNumber)
{
command_serial_new.Parameters["#slnr"].Value = SerialNumber;
try
{
var itExists = Convert.ToInt32(command_serial_new.ExecuteScalar()) > 0;
if (!itExists)
{
command_serial.Transaction = InsertUpdateSerialNumbers;
command_serial.CommandText = "INSERT INTO YSL00([Manifest_Number],[PONUMBER],[ITEMNMBR],[SERLNMBR]"
+ "VALUES ('" + Manifest + "','" + PONr + "','" + itemNumber + "','" + serialNr + "')";
var insertStatus = command_serial.ExecuteNonQuery();
return true;
}
}
catch (Exception ex)
{
LogException(ex, "Error in CheckSerialNumber =>"+ command_serial_new.CommandText.ToString());
}
return false;
}
I get error "Timeout expired. The timeout period elapsed prior to completion of the operation or server is not responding".
The CheckSerialNumber function also does an insert to YSL00 (the same table where I had executescalar. See code above).
As I mentioned earlier there are 1000s of line in a flat file that I read and update YSL000 table.
Note that I have two separate sqlcommands and also two separate connections to handle this. Reason is with sqltransaction it doesn't let me to query on the same table. I think timeout may be happening because of this?
Thanks for reading. Please suggest
Update 1: Since I have not pasted entire code, I want to mention that dispose is done using below code in the program.
if (conn != null)
{
conn.Close();
conn.Dispose();
}
if (conn_new != null)
{
conn_new.Close();
conn_new.Dispose();
}
you can increase the time out of your SqlConnection object.
you can do this with your ConnString:
string connStr = "Data Source=(local);Initial Catalog=AdventureWorks;Integrated
Security=SSPI;Connection Timeout=300";
I think default isolation level - read commited - is preventing your 'CheckSerialNumber' method from being effective. Command_serial_new will not take into consideration rows inserted in your loop - this might lead to some troubles. To be honest I would also look for some deadlock. Perhaps command_serial_new is actually completely blocked by the other transaction.
To start off:
Set command_serial_new query as:
SELECT 1 FROM YSL00 WITH (NOLOCK) WHERE SERLNMBR = #slnr
Think about using lower isolation level to query inserted rows as well (set it to read uncommited).
Close your connections and transactions.
Use just one SqlConnection - you don't need two of them.
Many of the objects you are using implement IDisposable, and you should be wrapping them with using statements. Without these using statements, .NET won't necessarily get rid of your objects until an undetermined time when the garbage collector runs, and could block subsequent queries if it's still holding a transaction open somewhere.
So for example, you'll need to wrap your connections with using statements:
using (conn_new = new SqlConnection(ConnString)) {
...
If I am not mistaken you need to merge the file content with the table content.
For this purpose I would recommend you
Copy the file content in to a temporary table (see temporary tables and BulkInsert)
Use command MERGE (http://msdn.microsoft.com/en-us/library/bb510625.aspx) to merge the temporary table content with the original table
I am writing a simple database backup and restore routine for an application. I can backup my database without issues, however when I restore is I am unable to gain exclusive access to my database.
I am trying all the combinations of fixes on SO, putting in single user mode, taking it offline then placing it back only with no success.
I can successfully restore the database within studio manager (express)
This method is the only connection to the SQL server at the time, so I don't understand why I can't perform the restore.
Appreciate the help to point out where the issue may be.
internal void RestoreDatabase(string databaseFile)
{
//get database details
var databaseConfiguration = new DatabaseConfiguration().GetDatabaseConfiguration();
try
{
//construct server connection string
var connection = databaseConfiguration.IsSqlAuthentication
? new ServerConnection(databaseConfiguration.ServerInstance,
databaseConfiguration.SqlUsername,
databaseConfiguration.SqlPassword)
: new ServerConnection(databaseConfiguration.ServerInstance);
//set database to single user and kick everyone off
using (
var sqlconnection =
new SqlConnection(new DatabaseConfiguration().MakeConnectionString(databaseConfiguration)))
{
sqlconnection.Open();
using (
var sqlcommand = new SqlCommand("ALTER DATABASE " + databaseConfiguration.DatabaseName + " SET Single_User WITH Rollback IMMEDIATE",
sqlconnection))
{
sqlcommand.ExecuteNonQuery();
}
using (
var sqlcommand = new SqlCommand("ALTER DATABASE " + databaseConfiguration.DatabaseName + " SET OFFLINE",
sqlconnection))
{
sqlcommand.ExecuteNonQuery();
}
using (
var sqlcommand = new SqlCommand("ALTER DATABASE " + databaseConfiguration.DatabaseName + " SET ONLINE",
sqlconnection))
{
sqlcommand.ExecuteNonQuery();
}
sqlconnection.Close();
}
//setup server connection and restore
var server = new Server(connection);
var restore = new Restore();
restore.Database = databaseConfiguration.DatabaseName;
restore.Action = RestoreActionType.Database;
restore.Devices.AddDevice(databaseFile, DeviceType.File);
restore.ReplaceDatabase = true;
restore.Complete += Restore_Complete;
restore.SqlRestore(server);
}
catch (Exception ex)
{
//my bad
restoreDatabaseServerError(ex.InnerException.Message, EventArgs.Empty);
}
finally
{
//set database to multi user
using (
var sqlconnection =
new SqlConnection(new DatabaseConfiguration().MakeConnectionString(databaseConfiguration)))
{
sqlconnection.Open();
using (
var sqlcommand = new SqlCommand("ALTER DATABASE " + databaseConfiguration.DatabaseName + " SET Multi_User",
sqlconnection))
{
sqlcommand.ExecuteNonQuery();
sqlcommand.Dispose();
}
sqlconnection.Close();
}
}
}
If anybody is connected to your database, SQL Server cannot drop it, so you have to disconnect existing connections, as you have tried. The problem with single_user is, that it still allows a single user to connect. As you yourself cannot be connected to the database when dropping it you have to get out of there. That opens up that slot for someone else to connect and in turn prevent you from dropping it.
There are a few SQL Server processes that are particularly good at connecting to a database in that split second. Replication is one example. (You shouldn't really drop a database that is published anyway, bat that is another story.)
So what can we do about this? The only 100% safe way is to prevent users from connecting to the database. The only practical way is to switch the database offline and then drop it. However, that has the nasty side effect, that SQL Server does not delete the files of that database, so you have to do that manually.
Another option is to just be fast enough. In your example you bring the database back online before you drop it. That is a fairly resource intensive process that gives an "intruder" lots of time to connect.
The solution I have been using with success looks like this:
ALTER DATABASE MyDb SET RESTRICTED_USER WITH ROLLBACK IMMEDIATE;
USE MyDb;
ALTER DATABASE MyDb SET SINGLE_USER WITH ROLLBACK IMMEDIATE;
USE tempdb;
DROP DATABASE MyDb;
This first sets the database to restricted user and connects to it. Then, while still connected it sets the database to single user. Afterwards the context is switched to tempdb and the drop is executed immediately thereafter. Important here is, to send these commands as one batch to SQL Server to minimize the time between the USE tempdb; and the DROP. Setting the database to restricted user in the beginning catches some rare edge cases, so leave it in even though it does not make sense at first glance.
While this still leaves a theoretical gap for someone else to get in, I have never seen it fail.
After the database is dropped you can run your restore as normal.
Good luck.
Your restore needs to take place on the same connection you set the DB server to single user mode.
In summary for the changes below, I moved the end of the using to below your restore code, and moved the close for the SQL connection to after the restore so it uses the same connection. Also removed set offline and online since they aren't needed. Can't test at the moment, so let me know if it works.
//set database to single user and kick everyone off
using (var sqlconnection = new SqlConnection(new DatabaseConfiguration().MakeConnectionString(databaseConfiguration)))
{
sqlconnection.Open();
using (var sqlcommand = new SqlCommand("ALTER DATABASE " + databaseConfiguration.DatabaseName + " SET Single_User WITH Rollback IMMEDIATE",sqlconnection))
{
sqlcommand.ExecuteNonQuery();
}
//setup server connection and restore
var server = new Server(sqlconnection);
var restore = new Restore();
restore.Database = databaseConfiguration.DatabaseName;
restore.Action = RestoreActionType.Database;
restore.Devices.AddDevice(databaseFile, DeviceType.File);
restore.ReplaceDatabase = true;
restore.Complete += Restore_Complete;
restore.SqlRestore(server);
sqlconnection.Close();
}
I have created a SQL Server Compact Database (.sdf file) and I want to be connected to it for do some insert , delete ... .
This is my creation code for it:
if (File.Exists(dbfilename))
File.Delete(dbfilename);
string connectionString = "Data Source=" + dbfilename + """;
SqlCeEngine engine = new SqlCeEngine(connectionString);
engine.CreateDatabase();
engine.Dispose();
SqlCeConnection conn = null;
try
{
conn = new SqlCeConnection(connectionString);
conn.Open();
SqlCeCommand cmd = conn.CreateCommand();
cmd.CommandText = "CREATE TABLE Contacts (ID uniqueidentifire, Address ntext)";
cmd.ExecuteNonQuery();
}
catch { }
finally
{
conn.Close();
}
Is it true?
How can I connect to it?
That connection string is broken.
"
is not a valid entity where you are trying to use it. Fix your connection string.
Also, you will need to associate the command with the connection, either in the constructor or after the fact.
Please read through an example such as this one, which was the first google result for "connect sql compact example c#":