I used Database first EF method to create a Model in a wpf application using C#. After adding relevant information, changing column's names, table's names, I want to copy it to a new location. But I get the error message that the database is in use.
using (var ctx = new TableGraphDBEntities())
{
for (int l = 0, m = 1; l < TableNames.Count; l++, m++)
{
string columnxQ = "sp_rename 'Table1.x','" + XNames[l] + "', 'COLUMN'";
string columnyQ = "sp_rename 'Table1.y','" + YNames[l] + "', 'COLUMN'";
string talbeQ = "sp_rename Table" + m.ToString() + "," + TableNames[l];
string detachQ = "sp_detach_db #dbname = N'TableGraphDB'";
//string setOffline = "
//string detachQ = "USE master; GO EXEC sp_detach_db #dbname = N'TableGraphDB'; GO";
ctx.Database.ExecuteSqlCommand(columnxQ);
ctx.Database.ExecuteSqlCommand(columnyQ);
ctx.Database.ExecuteSqlCommand(talbeQ);
ctx.Database.ExecuteSqlCommand(detachQ);
}
}
string oldFilePath = System.AppDomain.CurrentDomain.BaseDirectory + "TableGraphDB.mdf";
string FilePath = Properties.Settings.Default.ExtensionFileDir + #"\Saved DataBases\" + fnw.FileName + ".mdf";
if (File.Exists(FilePath))
{
MessageBox.Show("The database aleady exist, please type a different name");
return;
}
//FileInfo fileInfo = new FileInfo(oldFilePath);
//while (IsFileLocked(fileInfo))
//{
//}
File.Copy(oldFilePath, FilePath);
MessageBox.Show("Database is saved!");
Here is the link to slq command http://msdn.microsoft.com/en-gb/library/ms187858.aspx
The database is located in the Bin folder. It is copied as a new copy from the project each time I run the application. If I close the application and reopen it, it can be copied with all the data.
I tried using ExecuteSqlCommand(), but it didn't help. So how could I detach the database so that I could move/copy it?
Unfortunately StackOverFlow doesn't let me to answer my own question, so I have to write it down in here.
Answer:
First of all you have to check the actual name of your Database, it's not necessarily the name of the database file. In order to do that you need to:
Open the server explorer in Visual Studio or SQL Management Studio.
Open new query.
Execute the following query: SELECT name, create_date FROM sys.databases
Check the name of the database (in my case it was the full path of the database file, it can be only the name of the database or anything else.)
Then you can change the name of the columns and tables by executing the following code:
using (var ctx = new TableGraphDBEntities())
{
for (int l = 0, m = 1; l < TableNames.Count; l++, m++)
{
string columnxQ = "sp_rename 'Table1.x','" + XNames[l] + "', 'COLUMN'";
string columnyQ = "sp_rename 'Table1.y','" + YNames[l] + "', 'COLUMN'";
string talbeQ = "sp_rename Table" + m.ToString() + "," + TableNames[l];
ctx.Database.ExecuteSqlCommand(columnxQ);
ctx.Database.ExecuteSqlCommand(columnyQ);
ctx.Database.ExecuteSqlCommand(talbeQ);
ctx.Dispose();
}
}
And finally use the following code to detach and move it to a new location:
string oldFilePath = System.AppDomain.CurrentDomain.BaseDirectory + "TableGraphDB.mdf";
string conString = #"Data Source=(LocalDB)\v11.0;Integrated Security=True;";
using (System.Data.SqlClient.SqlConnection con = new System.Data.SqlClient.SqlConnection(conString))
{
string query = #"USE [master]
ALTER DATABASE ["+oldFilePath+#"] SET SINGLE_USER WITH ROLLBACK IMMEDIATE
USE [master]
EXEC master.dbo.sp_detach_db #dbname = N'"+oldFilePath+"'";
SqlCommand cmd = new SqlCommand(query, con);
con.Open();
cmd.ExecuteNonQuery();
cmd.Dispose();
con.Dispose();
}
string FilePath = Properties.Settings.Default.ExtensionFileDir + #"\Saved DataBases\" + fnw.FileName + ".mdf";
if (File.Exists(FilePath))
{
MessageBox.Show("The database aleady exist, please type a different name");
return;
}
File.Copy(oldFilePath, FilePath);
Note: If you try implement ctx.Database.ExecuteSqlCommand(query), you'll get the following error:
ALTER DATABASE statement not allowed within multi-statement transaction.
The procedure 'sys.sp_detach_db' cannot be executed within a transaction.
Changed database context to 'master'.
If you're using EF6 you may try this code:
string command = "EXEC sp_detach_db 'TableGraphDB', 'true'";
dbContext.ExecuteStoreCommand(command);
Second parameter in sp_detach_db procedure will drop all connections to this database
In SSMS this is the query that is used to detach a database.
Can you try this?
You should just be able to wrap the whole thing up as a string and execute it.
I'm not sure if it will be happy with the 'GO', so you might have to remove those.
string detachQ = "" +
"USE [master]\n" +
"GO\n" +
"ALTER DATABASE [TableGraphDB] SET SINGLE_USER WITH ROLLBACK IMMEDIATE\n" +
"GO\n" +
"USE [master]\n" +
"GO\n" +
"EXEC master.dbo.sp_detach_db #dbname = N'TableGraphDB'\n" +
"GO\n";
ctx.Database.ExecuteSqlCommand(detachQ);
Related
I have tried MANY suggested solutions from here but nothing seems to work for this problem. I just keep getting this error message when it hits the 'mdr = command.ExecuteReader();' line. Any thoughts please?
try
{
MySqlConnection connection = new MySqlConnection("SERVER=" + server + ";" + "DATABASE=" + database + ";" + "UID=" + uid + ";" + "PASSWORD=" + password + ";");
MySqlCommand command;
MySqlDataReader mdr;
connection.Open();
string ThePID = tbPID.Text;
string TheRound = tbRound.Text;
string CurrentPage = tbCurrentPage.Text;
// SELECT #myvar:= myvalue
string query = "SELECT ImageURL, ProofingText " +
"INTO #ImageURL, #ProofingText " +
"FROM Rounds " +
"WHERE ProjectID = " + ThePID + " " +
"AND CurrentRound = " + TheRound + " " +
"AND Page = " + CurrentPage + ";";
command = new MySqlCommand(query, connection);
mdr = command.ExecuteReader();
mdr.Read();
rtProofing.Text = mdr.GetString("#PRoofingText");
tbURL.Text = mdr.GetString("#ImageURL");
tbImagePage.Text = Path.GetFileName(tbURL.Text);
PageBox.Image = Image.FromFile(tbURL.Text);
connection.Close();
connection.Dispose();
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
If you use MySqlConnector, you will get a helpful exception message that explains the problem:
Parameter '#ImageURL' must be defined. To use this as a variable, set 'Allow User Variables=true' in the connection string.
By default, MySQL queries (executed from .NET) can't use user-defined variables. You can relax this limitation by adding Allow User Variables=true to your connection string.
However, this won't fix your underlying problem, which is that this isn't the right way to select data from MySQL.
Firstly, your query is susceptible to SQL injection; you should rewrite it to use parameters as follows:
using (var command = connection.CreateCommand())
{
command.CommandText = #"SELECT ImageURL, ProofingText
FROM Rounds
WHERE ProjectID = #ThePID
AND CurrentRound = #TheRound
AND Page = #CurrentPage;";
commands.Parameters.AddWithValue("#ThePID", ThePID);
commands.Parameters.AddWithValue("#TheRound", TheRound);
commands.Parameters.AddWithValue("#CurrentPage", CurrentPage);
Then, you can retrieve the values with a slight variation on your current code. You must retrieve the values by their column names, which do not have a leading #. You should also check that a row was retrieved by examining the return value of Read():
if (mdr.Read())
{
rtProofing.Text = mdr.GetString("ProofingText");
tbURL.Text = mdr.GetString("ImageURL");
}
Finally, string concatenation is also not the right way to build a connection string. The MySqlConnectionStringBuilder class exists for this purpose; use it.
var builder = new MySqlConnectionStringBuilder
{
Server = server,
Database = database,
UserID = uid,
Password = password,
};
using var connection = new MySqlConnection(csb.ConnectionString);
Building a tool to backup a database that I'm testing locally first. I'm trying to check if compression is supported and change my SQL query based on the value returned. Running it against an actual live server returns 0 or 1, but running the query itself against a local instance doesn't give a value. As a result I don't believe the if statements ever run to change the CommandText and my final WriteLine test returns the initial compression query instead of one of the backup commands.
I tried changing the if to check for a null, however the else should catch any other values besides '1'
string compressionQuery = "SELECT VALUE FROM sys.configurations WHERE name = 'backup compression default'";
SqlCommand sqlCmd = new SqlCommand(compressionQuery, newConn);
SqlDataReader reader = sqlCmd.ExecuteReader();
while (reader.Read()) //while the data reader is checking the records
{
Interface.WriteLine(reader.GetInt32(0).ToString()); //print the specified record(row) to the console
canCompress = reader.GetInt32(0);
// Backup the database.
if (canCompress == 1)
{
sqlCmd.CommandText = "BACKUP DATABASE [" + connBuilder.InitialCatalog + "] "
+ "TO DISK = '" + backupPath + "' "
+ "WITH COPY_ONLY, COMPRESSION, NOFORMAT, NOINIT, "
+ "NAME = '" + backupName + "', "
+ "SKIP, REWIND, NOUNLOAD, STATS = 10";
Interface.WriteLine("1");
}
else
{
sqlCmd.CommandText = "BACKUP DATABASE [" + connBuilder.InitialCatalog + "] "
+ "TO DISK = '" + backupPath + "' "
+ "WITH COPY_ONLY, NOFORMAT, NOINIT, "
+ "NAME = '" + backupName + "', "
+ "SKIP, REWIND, NOUNLOAD, STATS = 10";
Interface.WriteLine("0");
}
}
reader.Close(); //stop reading records
Interface.WriteLine(sqlCmd.CommandText.ToString()); //Should print one of the backup queries
sqlCmd.ExecuteNonQuery();
It should return one of the nested backup commands. Right now it simply writes the initial compression query.
Backup compression is not available in all editions of SQL Server. So in my sqlexpress the value is not even in the table, it is probably your case too. reader.Read() never reads anything, so you do not get into the if part at all. You can restructuralize you code
bool canCompress = false;
using (SqlDataReader reader = sqlCmd.ExecuteReader())
{
while (reader.Read())
{
canCompress = reader.GetInt32(0) == 1;
}
}
if (canCompress)
{
...
}
else
{
...
}
And you can even simplify the reading like this
bool canCompress = (int?)sqlCmd.ExecuteScalar() == 1;
The following code gets a value which indicates whether backup compression is supported and, if so, whether it is enabled by default.
using (SqlConnection dbConnection = new SqlConnection("Your connection string.")
{
dbConnection.Open();
using (SqlCommand dbCommand = new SqlCommand(
"select value from sys.configurations where name = 'backup compression default';", dbConnection))
{
// The values are:
// null Backup compression is not supported.
// 0 Backup compression is supported and disabled by default.
// 1 Backup compression is supported and enabled by default.
int? backupCompressionDefault = (int?)dbCommand.ExecuteScalar();
}
dbConnection.Close();
}
Note that the value column in sys.configurations is declared as sql_variant. The actual type returned can be displayed thusly:
select SQL_VARIANT_PROPERTY( value, 'basetype' )
from sys.configurations
where name = 'backup compression default';
I am trying to update database records over a range in Access using SQL and C#. Using an UPDATE query keeps giving me an error
Syntax error (missing operator) in query expression
All of the query criteria is from user input. I have tried a number of sources to find an answer but I believe my SQL statement is correct. Below is the method that is performing the task that I need.
private void btnUpdate_Click(object sender, EventArgs e)
{
int teamYear = Convert.ToInt32(this.textBoxBegYear.Text);
int endYear = Convert.ToInt32(this.textBoxEndYear.Text);
string teamName = this.textBoxTeamName.Text;
string league = this.textBoxLeague.Text;
string conference = this.textBoxConf.Text;
string division = this.textBoxDivision.Text;
try
{
dbConn = new OleDbConnection();
dbConn.ConnectionString = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source="
+ ch + openFileDialog1.FileName + ch;
dbConn.Open();
sql = "UPDATE " + this.comboBox1.SelectedItem.ToString()
+ " SET LeagueName = #leagueName, ConferenceName = #conferenceName,
DivisionName = #divisionName WHERE TeamName = " + this.textBoxTeamName.Text
+ " AND TeamYear BETWEEN " + this.textBoxBegYear.Text
+ " AND " + this.textBoxEndYear.Text;
dbCmd = new OleDbCommand(sql, dbConn);
for (int i = teamYear; i <= endYear; i++)
{
dbCmd.Parameters.AddWithValue("#leagueName", league);
dbCmd.Parameters.AddWithValue("#conferenceName", conference);
dbCmd.Parameters.AddWithValue("#divisionName", division);
dbCmd.ExecuteNonQuery();
}
dbCmd.Connection.Close();
dbConn.Close();
}
catch (Exception err)
{
MessageBox.Show("Error: " + err.Message.ToString());
}
}
The exception comes from the second half of the SQL statement after the WHERE clause asking for a missing operator.
Can anyone happen to see what I may be missing? Any help would be appreciated.
Why don't you replace the code in the "try" block to this:
dbConn = new OleDbConnection();
dbConn.ConnectionString = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source="
+ ch + openFileDialog1.FileName + ch;
dbConn.Open();
sql = "UPDATE " + this.comboBox1.SelectedItem.ToString()
+ " SET LeagueName = #leagueName, ConferenceName = #conferenceName,
DivisionName = #divisionName WHERE TeamName = #teamName AND TeamYear BETWEEN #begYear AND #endYear";
dbCmd = new OleDbCommand(sql, dbConn);
for (int i = teamYear; i <= endYear; i++)
{
dbCmd.Parameters.AddWithValue("#leagueName", league);
dbCmd.Parameters.AddWithValue("#conferenceName", conference);
dbCmd.Parameters.AddWithValue("#divisionName", division);
dbCmd.Parameters.AddWithValue("#teamName", this.textBoxTeamName.Text);
dbCmd.Parameters.AddWithValue("#begYear", int.Parse(this.textBoxBegYear.Text));
dbCmd.Parameters.AddWithValue("#endYear", int.Parse(this.textBoxBegYear.Text));
dbCmd.ExecuteNonQuery();
}
dbCmd.Connection.Close();
dbConn.Close();
Therefore, you have better idea what the SQL query looks like, and you parameterize users' input to improve security (prevent any sql injection).
To troubleshoot your issue, you may need to debug into this piece of code and see what's the SQL query is, and try to execute it from your SQL client tool (such as Sql management studio), you will have better idea what goes wrong.
Hope this helps.
Henry Liang
You might be missing single quotes '...
TeamName = '" + this.textBoxTeamName.Text + "'
Also, I'm assuming this is just a project you're playing around with and nothing that will be available online? Reason I ask is that the SQL query is vulnerable to SQL injection attacks.
You need to escape the text from the user input with single quotes.
WHERE TeamName = '" + this.textBoxTeamName.Text
+ "' AND TeamYear BETWEEN " + this.textBoxBegYear.Text
+ " AND " + this.textBoxEndYear.Text;
(Notice the single quotes).
Please do not use the code you posted. Please read up on SQL Injection attacks and why your code is very unsafe and replace it with some properly cleaned input handling.
I'm using following code to restore a BAK file to an MDF file, initially I create a database and then try to restore it using my BAK file, but I get some errors:
I use an open file dialog to select my BAK file
openDialogConvert.ShowDialog();
RegistryKey rk = Registry.LocalMachine.OpenSubKey(#"SOFTWARE\Microsoft\Microsoft SQL Server");
String[] instances = (String[])rk.GetValue("InstalledInstances");
string sqlname = "";
if (instances.Length > 0)
{
foreach (String element in instances)
{
if (element == "MSSQLSERVER")
sqlname = System.Environment.MachineName;
else
sqlname = System.Environment.MachineName + #"\" + element;
}
}
String str;
SqlConnection myConn = new SqlConnection("Server=" + sqlname + ";Integrated security=SSPI;database=master");
string dbname = "tmpDB" + DateTime.Now.Ticks.ToString();
str = "CREATE DATABASE " + dbname + " ON PRIMARY " +
"(NAME = MyDatabase_Data, " +
"FILENAME = '" + Environment.CurrentDirectory + "\\" + dbname + ".mdf') " +
"LOG ON (NAME = MyDatabase_Log, " +
"FILENAME = '" + Environment.CurrentDirectory + "\\" + dbname + ".ldf') ";
SqlCommand myCommand = new SqlCommand(str, myConn);
try
{
myConn.Open();
myCommand.ExecuteNonQuery();
MessageBox.Show("DataBase is Created Successfully", "MyProgram", MessageBoxButtons.OK, MessageBoxIcon.Information);
}
catch (System.Exception ex)
{
MessageBox.Show(ex.ToString(), "MyProgram", MessageBoxButtons.OK, MessageBoxIcon.Information);
}
myCommand.Dispose();
str = #"RESTORE DATABASE [" + dbname + "] FROM DISK = N'" + openDialogConvert.FileName + #"' WITH MOVE N'IODB_Data'
TO N'" + Environment.CurrentDirectory + #"\\" + dbname + #".mdf', MOVE N'IODB_Log'
TO N'" + Environment.CurrentDirectory + #"\\" + dbname + #".ldf', REPLACE ";
myCommand = new SqlCommand(str, myConn);
myCommand.ExecuteNonQuery();
myCommand.Dispose();
myConn.Close();
my new (empty) database is created successfully but I get strange errors while trying to restore the BAK file in this newly created database.
I get following error using the above code:
The operating system returned the error '32(failed to retrieve text
for this error. Reason: 15105)' while attempting
'RestoreContainer::ValidateTargetForCreation' on 'D:\7 mordad
fara\Ofogh-Dsk\Ofogh-Dsk\bin\Debug\tmpDB635107927412887254.mdf'.
File 'IODB_Data' cannot be restored to 'D:\7 mordad
fara\Ofogh-Dsk\Ofogh-Dsk\bin\Debug\tmpDB635107927412887254.mdf'. Use
WITH MOVE to identify a valid location for the file.
The operating system returned the error '32(failed to retrieve text
for this error. Reason: 15105)' while attempting
'RestoreContainer::ValidateTargetForCreation' on 'D:\7 mordad
fara\Ofogh-Dsk\Ofogh-Dsk\bin\Debug\tmpDB635107927412887254.ldf'.
File 'IODB_Log' cannot be restored to 'D:\7 mordad
fara\Ofogh-Dsk\Ofogh-Dsk\bin\Debug\tmpDB635107927412887254.ldf'. Use
WITH MOVE to identify a valid location for the file.
Problems were identified while planning for the RESTORE statement. Previous messages provide details.
RESTORE DATABASE is terminating abnormally.
but when I insert a 'GO' at the end my command, I get following error:
Incorrect syntax near GO
what is going wrong here?
of course I've tested the restore operation successfully with SQL server management studio and I've found correct logical names for my BAK file (in fact I've copied the script from MSSMS)
You can also try this.
Step 1 - connect the database server using MS SQL Server Management
Studio.
step 2 - Find the database in the left pane & right-click to choose
the restore option.
Step 3 - Choose the destination and source for restoration.
Step 4 - Browse for the backup file from the device & click on ok
Step 5 - Select the database you want to restore from the list and
click ok.
After completing the restore process, your database will be ready to use.
Note: You must create a new database to restore the old one.
I am attempting to dynamically update a set of database tables. I have two variables;
table_name & field_name. These are populated by a foreach loop, that loops through a DataTable. Everytime we hit a new row in the DataTable the names change respectively. Within this loop I create a new Oracle Connection and attempt to write an update with the current table_name/field_name. But Oracle keeps giving me an error on my ExcecuteNonQuery command.
Any help is greatly appreciated!!
EDIT: I have reformatted to include parameters, still does not work does anyone have any ideas on what I am doing wrong?
foreach (DataRow fieldtable in setofTables.Tables[0].Rows)
{
//do work
table_name = fieldtable["table_name"].ToString().Trim();
field_name = fieldtable["field_name"].ToString().Trim();
MessageBox.Show(table_name + field_name);
//create parameters
OracleParameter fieldParamater = new OracleParameter("field_name", OracleDbType.Varchar2);
OracleParameter diffParameter = new OracleParameter("mark_diff_oracle", OracleDbType.BinaryFloat);
OracleParameter wellIdParameter = new OracleParameter("id", OracleDbType.Char);
//wellIdParameter.Size = 10;
//create oracle connection and open
OracleConnection OrclCon2 = new OracleConnection("Data Source=" + dbname + "; User Id=" + userid + ";Password=" + password1 + ";");
OrclCon2.Open();
//prepare sql to be passed to oracle
string UpdateOraSQL = "UPDATE " +table_name+ " set :field_name = :field_name - (:mark_diff_oracle) where id = ':id' and :field_name is not null;";
MessageBox.Show(UpdateOraSQL);
//create dommand
OracleCommand UpdateDB = new OracleCommand(UpdateOraSQL, OrclCon2);
UpdateDB.CommandType = CommandType.Text;
//add parameters
UpdateDB.Parameters.Clear();
UpdateDB.Prepare();
UpdateDB.Parameters.Add(fieldParamater).Value = field_name;
UpdateDB.Parameters.Add(diffParameter).Value = mark_diff_oracle;
UpdateDB.Parameters.Add(wellIdParameter).Value = id;
Remove the semicolon from the end of the sql statement. Change the following code
string UpdateOraSQL = "UPDATE " +table_name+ " set :field_name = :field_name - (:mark_diff_oracle) where id = ':id' and :field_name is not null;";
to
string UpdateOraSQL = "UPDATE " +table_name+ " set :field_name = :field_name - (:mark_diff_oracle) where id = ':id' and :field_name is not null";
See the following link for more information
why the semicolon couldn't place in the CommandText of a OracleCommand when C#
If the problem is still not resolved, it might be helpful if you post the entire exception message also.
AFAIK, you cannot use parameters to define the column that you're updating.
AFAIK, you can only use parameters for the values that you'd want to set.
So, you'll have to create the query using string concat:
string sql = "UPDATE " + tableName + " SET " + fieldName + " = :p_Value WHERE id = :p_Id";
OracleCommand UpdateDB = new OracleCommand(sql, OrclCon2);
UpdateDB.Parameters.Add ("p_Value", ... ).Value = "foo";
UpdateDB.Parameters.Add ("p_Id", ...).Value = 4;
Offcourse, you should make sure that the variables you're adding to the string do not contain any harmfull statements. You should do sanity checks on them.
Perhaps, you can even verify if the tableName or the fieldName that has been passed, is a valid / existing tableName/columnname.
In SQL, one does not say COLUMN <> NULL. The proper syntax is COLUMN IS NOT NULL.