I'm running SQL script from C# code, my problem that the code take a long time to finish execution, it has many tables to be created in script(at least 30 Tables), so my code is working but it has performance issue.
this is the code
public static bool executeSqlScript(string scriptPath,string serverName,string databaseName)
{
try
{
SqlConnection myConn = new SqlConnection("Server=.;Integrated security=SSPI;database=master");
Server server = new Server(new ServerConnection(myConn));
string CreateCommand = "CREATE DATABASE " + databaseName + "";
string appendText;
//delete first line from script(Oldscript)
var lines = File.ReadAllLines(scriptPath).Skip(1);
File.WriteAllLines(scriptPath, lines);
using (StreamReader sreader = new StreamReader(scriptPath))
{
appendText = sreader.ReadToEnd();
}
File.Delete(scriptPath);
using (StreamWriter swriter = new StreamWriter(scriptPath, false))
{
appendText = "USE [" + databaseName + "]" + Environment.NewLine + appendText;
swriter.Write(appendText);
swriter.Close();
}
string readtext = File.ReadAllText(scriptPath);
SqlCommand myCommand = new SqlCommand(CreateCommand, myConn);
myConn.Open();
myCommand.ExecuteNonQuery();
server.ConnectionContext.ExecuteNonQuery(readtext);
return true;
}
catch (Exception e)
{
throw e;
return false;
}
}
My recommendation would be to migrate most of this to the SQL Server, once the new DB and User are setup, call a Stored Procedure to read the SQL file with the necessary DDL in it.
My last project was for a managed hosting company, and our CMS utilized well over 150 database objects. We used a "control" database which we pass in the new DB information and it would ceate the new tables, functions, and procedures generally in less than a minute.
use Parallel.ForEach to create tables likes
public static bool executeSqlScript(string scriptPath, string serverName, string databaseName)
{
try
{
SqlConnection myConn = new SqlConnection("Server=.;Integrated security=SSPI;database=master");
//Server server = new Server(new ServerConnection(myConn));
string CreateCommand = "CREATE DATABASE " + databaseName + "";
string appendText;
//delete first line from script(Oldscript)
//create db first
var myCommand = new SqlCommand(CreateCommand, myConn);
myConn.Open();
myCommand.ExecuteNonQuery();
myConn.Close();
List<string[]> list = File.ReadLines(scriptPath)
.Select(line => line.ToLower().Split(new string[] { "go" }, StringSplitOptions.None))
.ToList();
Parallel.ForEach(list, (sql) =>
{
using (var mysqlConn = new SqlConnection("Server=.;Integrated security=SSPI;database=master"))
{
var mysql = "USE [" + databaseName + "]" + Environment.NewLine + string.Join("", sql);
var mysqlCommand = new SqlCommand(mysql, mysqlConn);
myConn.Open();
mysqlCommand.ExecuteNonQuery();
}
});
//server.ConnectionContext.ExecuteNonQuery(readtext);
return true;
}
catch (Exception e)
{
throw e;
return false;
}
}
The problem was in Go Keyword in script, I Found this solution
http://www.codingdefined.com/2014/07/run-sql-script-file-in-c.html
(If you are trying to execute a SQL generated script file you have to remove all "GO". For that you have to use the following code...)
Here is my code:
string sqlConnectionString = "Data Source=.;Initial Catalog=master;Integrated Security=True";
FileInfo file = new FileInfo(#"D:\Script.sql");
string script = file.OpenText().ReadToEnd();
SqlConnection conn = new SqlConnection(sqlConnectionString);
conn.Open();
script = script.Replace("GO", "");
SqlCommand cmd = new SqlCommand(script, conn);
cmd.ExecuteNonQuery();
cmd.Dispose();
conn.Close();
Related
I want to create a database User in C#. In Microsoft SQL Server Management Studio I just can create one with the following command:
CREATE USER [DOMAIN\user]
But when I try to do the same in C# I can't send a single backslash in the command.
string query = #"CREATE USER [DOMAIN\user]";
I already tried things like query.Replace("\\\\", "\\") or query.Replace(#"\\\\", #"\\"), but nothing worked for me. I always get an error with:
Incorrect syntax near '\\'.
It's the same like I would write CREATE USER [DOMAIN\\\\user] in SQL Server Management Studio.
Somehow I can't transfer just one backslash in the query.
Does anyone have a hint for me?
Thats my actual code:
public SqlConnection Conn;
public bool CreateUser(string LoginName)
{
string dom_login = Domain + "\\" + LoginName;
string query = #"CREATE USER [" + dom_login.Replace("\\",#"\") + "]";
// now query should be okay, so send to sql connection
DataTable dt = new DataTable();
if (Conn.State == ConnectionState.Closed)
Conn.Open();
try
{
SqlDataAdapter sDataAsp = new SqlDataAdapter(query, Conn);
sDataAsp.Fill(dt);
}
catch (Exception ex)
{
// Here i get the syntax error
string error = ex.Message;
return false;
}
return true;
}
Solved:
private bool ExecuteQuery(string domain, string user)
{
try
{
string dom_login = domain + #"\" + user;
string query = #"CREATE USER [" + dom_login + "]";
if (Conn.State == ConnectionState.Closed)
Conn.Open();
SqlCommand command = new SqlCommand(query, Conn);
command.ExecuteNonQuery();
}
catch (Exception ex)
{
error = ex.Message;
return false;
}
return true;
}
I have two almost same databases (both are *.mdb), but one of them has few new tables. Now I can only detect tables, that should be imported, using code below:
public static List<string> GetDBTables(string path)
{
List<string> allTables = new List<string>();
String connect = ("Provider=Microsoft.JET.OLEDB.4.0;data source="
+ path + ";Persist Security Info=False;");
OleDbConnection con = new OleDbConnection(connect);
con.Open();
DataTable tables = con.GetOleDbSchemaTable(OleDbSchemaGuid.Tables,
new object[] { null, null, null, "TABLE" });
int counter = 1;
foreach (DataRow row in tables.Rows)
{
allTables.Add(row[2].ToString());
counter++;
}
con.Close();
return allTables;
}
var withNewTables = GetDBTables(".\\one.mdb");
var withoutNewTables = GetDBTables(".\\another.mdb");
var NotFoundTables = withNewTables.Except(withoutNewTables).ToList();
How can I import these tables in the old database using C #?
Access SQL offers two features which are useful here.
SELECT <field list> INTO NewTable
FROM table_name IN 'path to other db file'
So I can execute this statement from an OleDb connection to my destination db file, and it will create tblFoo_copy from the data contained in tblFoo in the other db file, NewData.mdb.
SELECT f.* INTO tblFoo_copy
FROM tblFoo AS f IN 'C:\Users\hans\Documents\NewData.mdb';
Build and execute similar statements for each of those tables you want to import.
Well, in addition to HansUp answer, I post the implementation of this on C#:
public static void insertTables(string path_from, string path_to,
List<string> _tables)
{
string conString = ("Provider=Microsoft.JET.OLEDB.4.0;data source="
+ path_to + ";Persist Security Info=False;");
OleDbConnection dbconn = new OleDbConnection(conString);
dbconn.Open();
OleDbCommand dbcommand = new OleDbCommand();
_tables.ForEach(delegate(String name)
{
string selQuery = "SELECT f.* INTO " + name + " FROM " + name
+ " AS f IN '" + path_from + "';";
dbcommand.CommandText = selQuery;
dbcommand.CommandType = CommandType.Text;
dbcommand.Connection = dbconn;
int result = dbcommand.ExecuteNonQuery();
});
dbconn.Close();
}
insertTables(".\\one.mdb", ".\\another.mdb", NotFoundTables);
i have this code for insert data into access 2013
after click in the save button data insert into dataGridView and show
and when stop program and restart this,data not stored in the DB.I've done a lot of searches but can't find the solution. my class code and my button save code
class DB
{
public static OleDbConnection con = new OleDbConnection();
static DB()
{
con.ConnectionString = "Provider=MICROSOFT.ACE.OLEDB.12.0; " +
"Data Source=|DataDirectory|//Phonebook-db.accdb;Persist Security Info=True";
}
public static void Insert(Person p1)
{
try
{
OleDbCommand cmd = con.CreateCommand();
con.Open();
string s = "INSERT INTO Industrialist (S_Name,S_Family,S_Telephone,S_Major)VALUES('" + p1.Name + "','" + p1.Family + "','" + p1.Telephone + "','" + p1.Major + "')";
cmd.CommandType = CommandType.Text;
cmd.CommandText = s;
cmd.ExecuteNonQuery();
con.Close();
System.Windows.Forms.MessageBox.Show("Record successfully Added");
}
catch (OleDbException exp) { MessageBox.Show(exp.ToString()); }
}
}
Person p = new Person();
p.Name = txtname.Text;
p.Family = txtfamily.Text;
p.Telephone = txttell.Text;
p.Major = txtmajor.Text;
DB.Insert(p);
txttell.Text = "";
txtmajor.Text = "";
txtname.Text = "";
txtfamily.Text = "";
List<Person> people = DB.GetPeople();
dataGridView1.DataSource = people;
Choose your ACCDB file listed in your project files, select Copy To Output Directory and set its value to Never (And remember that |DataDirectory| is a substitution strings that points (for ASP.NET projects) to APP_DATA, your record is inserted in the database copied in that directory.
Said that please consider to use a parameterized query to create an sql command, not string concatenations
try
{
OleDbCommand cmd = con.CreateCommand();
con.Open();
string s = "INSERT INTO Industrialist (S_Name,S_Family,S_Telephone,S_Major)VALUES(" +
"?,?,?,?)";
cmd.CommandText = s;
cmd.Parameters.AddWithValue("#p1",p.Name);
cmd.Parameters.AddWithValue("#p2",p.Family);
cmd.Parameters.AddWithValue("#p3",p.Telephone);
cmd.Parameters.AddWithValue("#p4",p.Major);
cmd.ExecuteNonQuery();
con.Close();
System.Windows.Forms.MessageBox.Show("Record successfully Added");
}
catch (OleDbException exp) { MessageBox.Show(exp.ToString()); }
Of course do not close the connection before executing the command.
Another point to change is the usage pattern of your connection. Do not create a global connection and keep it around for the lifetime of your application. Simply create and use it when needed and close/dispose immediately after
using(OleDbConnection con = new OleDbConnection("Provider=MICROSOFT.ACE.OLEDB.12.0; " +
"Data Source=|DataDirectory|//Phonebook-db.accdb;" +
"Persist Security Info=True"))
{
try
{
OleDbCommand cmd = con.CreateCommand();
....
}
} // <- Here at the closing brace the connectio will be close and disposed
bool ret = false;
try
{
SQLiteConnection sqlConn = new SQLiteConnection("Data Source=" + m_dbName);
sqlConn.Open();
SQLiteCommand sqlComm = sqlConn.CreateCommand();
sqlComm.CommandText = "DELETE FROM " + szTablename+" WHERE name="+name+"";
SQLiteDataAdapter sqlAdapter = new SQLiteDataAdapter(sqlComm);
if (null == sqlAdapter)
{
ret = false;
}
else
{
ret = true;
}
sqlConn.Close();
return ret;
}
catch (SQLiteException sqlEx)
{
Console.WriteLine(sqlEx.Message);
return false ;
}
I have that code to delete a row in an sqlite database, but nothing is done after I click the delete button.
Instead of using a DataAdapter you could just execute the command directly:
using(SQLiteConnection sqlConn = new SQLiteConnection("Data Source=" + m_dbName))
{
sqlConn.Open();
//create command
sqlCommand.ExecuteNonQuery();
}
You shouldn't swallow any exceptions that get thrown from the ExecuteNonQuery method unless you can sensibly handle them. You should use parameterised queries instead of manually creating the queries by concatenating strings. You should also make sure you close the connection after you have finished using it as shown.
Try with single quotes:
sqlComm.CommandText = "DELETE FROM " + szTablename+" WHERE name='"+name+"'";
Have you tried using like instead of =
inside the query:
sqlComm.CommandText = "DELETE FROM " + szTablename+" WHERE name="+name+""
as this:
sqlComm.CommandText = "DELETE FROM " + szTablename+" WHERE name like "+name+""
using (SQLiteCommand com = new SQLiteCommand(con))
{
com.CommandText = "DELETE FROM " + szTablename + " WHERE name='" + name + "';";
com.ExecuteNonQuery();
com.Dispose();
}
I try to restore the database like this:
SQL = #"RESTORE DATABASE MyDataBase TO DISK='d:\MyDATA.BAK'";
Cmd = new SqlCommand(SQL, Conn);
Cmd.ExecuteNonQuery();
Cmd.Dispose();
but I always get error:
Msg 3102, Level 16, State 1, Line 7
RESTORE cannot process database 'MyDataBase ' because it is in use
by this session. It is recommended that the master database be used
when performing this operation.
Msg 3013, Level 16, State 1, Line 7
RESTORE DATABASE is terminating abnormally.
I prefer to use SMO to restore a backup:
Microsoft.SqlServer.Management.Smo.Server smoServer =
new Server(new ServerConnection(server));
Database db = smoServer.Databases['MyDataBase'];
string dbPath = Path.Combine(db.PrimaryFilePath, 'MyDataBase.mdf');
string logPath = Path.Combine(db.PrimaryFilePath, 'MyDataBase_Log.ldf');
Restore restore = new Restore();
BackupDeviceItem deviceItem =
new BackupDeviceItem('d:\MyDATA.BAK', DeviceType.File);
restore.Devices.Add(deviceItem);
restore.Database = backupDatabaseTo;
restore.FileNumber = restoreFileNumber;
restore.Action = RestoreActionType.Database;
restore.ReplaceDatabase = true;
restore.SqlRestore(smoServer);
db = smoServer.Databases['MyDataBase'];
db.SetOnline();
smoServer.Refresh();
db.Refresh();
You'll need references to Microsoft.SqlServer.Smo, Microsoft.SqlServer.SmoExtended, and Microsoft.SqlServer.Management.Sdk.Sfc
Your DB connection is most likely to the database you're trying to restore. So there is a DB shared lock which prevents the restore of your db
Try this
SQL = #"USE master BACKUP DATABASE MyDataBase TO DISK='d:\MyDATA.BAK'";
Or change the connection details to use master DB
public void Restore(string Filepath)
{
try
{
if(con.State == ConnectionState.Closed)
{
con.Open();
}
SqlCommand cmd1 = new SqlCommand("ALTER DATABASE [" + Database + "] SET SINGLE_USER WITH ROLLBACK IMMEDIATE ", con);
cmd1.ExecuteNonQuery();
SqlCommand cmd2 = new SqlCommand("USE MASTER RESTORE DATABASE [" + Database + "] FROM DISK='" + Filepath + "' WITH REPLACE", con);
cmd2.ExecuteNonQuery();
SqlCommand cmd3 = new SqlCommand("ALTER DATABASE [" + Database + "] SET MULTI_USER", con);
cmd3.ExecuteNonQuery();
con.Close();
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
con.Close();
}
You must connect to the database server via a different database.
So your connection string should take you to say "Master" or another database on the server, then you can complete the task at hand.
Your connection string should have a master database as default catalog to connect to.
I've ended with this solution. Name of my database was Stats This will work without installed MSSQL management studio
public void BackUpDB(string fname)
{
using (SqlConnection cn = new SqlConnection(_cstr))
{
cn.Open();
string cmd = "BACKUP DATABASE [Stats] TO DISK='" + fname + "'";
using (var command = new SqlCommand(cmd, cn))
{
command.ExecuteNonQuery();
}
}
}
public void RestoreDB(string fname)
{
using (SqlConnection cn = new SqlConnection(_cstr))
{
cn.Open();
#region step 1 SET SINGLE_USER WITH ROLLBACK
string sql = "IF DB_ID('Stats') IS NOT NULL ALTER DATABASE [Stats] SET SINGLE_USER WITH ROLLBACK IMMEDIATE";
using (var command = new SqlCommand(sql, cn))
{
command.ExecuteNonQuery();
}
#endregion
#region step 2 InstanceDefaultDataPath
sql = "SELECT ServerProperty(N'InstanceDefaultDataPath') AS default_file";
string default_file = "NONE";
using (var command = new SqlCommand(sql, cn))
{
using (var reader = command.ExecuteReader())
{
if (reader.Read())
{
default_file = reader.GetString(reader.GetOrdinal("default_file"));
}
}
}
sql = "SELECT ServerProperty(N'InstanceDefaultLogPath') AS default_log";
string default_log = "NONE";
using (var command = new SqlCommand(sql, cn))
{
using (var reader = command.ExecuteReader())
{
if (reader.Read())
{
default_log = reader.GetString(reader.GetOrdinal("default_log"));
}
}
}
#endregion
#region step 3 Restore
sql = "USE MASTER RESTORE DATABASE [Stats] FROM DISK='" + fname + "' WITH FILE = 1, MOVE N'Stats' TO '" + default_file + "Stats.mdf', MOVE N'Stats_Log' TO '"+ default_log+ "Stats_Log.ldf', NOUNLOAD, REPLACE, STATS = 1;";
using (var command = new SqlCommand(sql, cn))
{
command.ExecuteNonQuery();
}
#endregion
#region step 4 SET MULTI_USER
sql = "ALTER DATABASE [Stats] SET MULTI_USER";
using (var command = new SqlCommand(sql, cn))
{
command.ExecuteNonQuery();
}
#endregion
}
}