/************************************************************************************ * * Umbraco Data Layer * MIT Licensed work * ©2008 Ruben Verborgh * ***********************************************************************************/ using System; using System.Collections.Generic; using System.Data; using System.Data.SqlServerCe; using System.Linq; using System.Xml; using System.Diagnostics; using umbraco.DataLayer; using umbraco.DataLayer.SqlHelpers.SqlServer; namespace SqlCE4Umbraco { /// /// Sql Helper for an SQL Server database. /// public class SqlCEHelper : SqlHelper { /// /// Initializes a new instance of the class. /// /// The connection string. public SqlCEHelper(string connectionString) : base(connectionString) { m_Utility = new SqlCEUtility(this); } /// /// Checks if the actual database exists, if it doesn't then it will create it /// internal void CreateEmptyDatabase() { var localConnection = new SqlCeConnection(ConnectionString); if (!System.IO.File.Exists(ReplaceDataDirectory(localConnection.Database))) { var sqlCeEngine = new SqlCeEngine(ConnectionString); sqlCeEngine.CreateDatabase(); // SD: Pretty sure this should be in a using clause but i don't want to cause unknown side-effects here // since it's been like this for quite some time //using (var sqlCeEngine = new SqlCeEngine(ConnectionString)) //{ // sqlCeEngine.CreateDatabase(); //} } } /// /// Most likely only will be used for unit tests but will remove all tables from the database /// internal void ClearDatabase() { // drop constraints before tables to avoid exceptions // looping on try/catching exceptions was not really nice // http://stackoverflow.com/questions/536350/drop-all-the-tables-stored-procedures-triggers-constriants-and-all-the-depend var localConnection = new SqlCeConnection(ConnectionString); if (System.IO.File.Exists(ReplaceDataDirectory(localConnection.Database))) { List tables; // drop foreign keys // SQL may need "where constraint_catalog=DB_NAME() and ..." tables = new List(); using (var reader = ExecuteReader("select table_name from information_schema.table_constraints where constraint_type = 'FOREIGN KEY' order by table_name")) { while (reader.Read()) tables.Add(reader.GetString("table_name").Trim()); } foreach (var table in tables) { var constraints = new List(); using (var reader = ExecuteReader("select constraint_name from information_schema.table_constraints where constraint_type = 'FOREIGN KEY' and table_name = '" + table + "' order by constraint_name")) { while (reader.Read()) constraints.Add(reader.GetString("constraint_name").Trim()); } foreach (var constraint in constraints) { // SQL may need "[dbo].[table]" ExecuteNonQuery("alter table [" + table + "] drop constraint [" + constraint + "]"); } } // drop primary keys // SQL may need "where constraint_catalog=DB_NAME() and ..." tables = new List(); using (var reader = ExecuteReader("select table_name from information_schema.table_constraints where constraint_type = 'PRIMARY KEY' order by table_name")) { while (reader.Read()) tables.Add(reader.GetString("table_name").Trim()); } foreach (var table in tables) { var constraints = new List(); using (var reader = ExecuteReader("select constraint_name from information_schema.table_constraints where constraint_type = 'PRIMARY KEY' and table_name = '" + table + "' order by constraint_name")) { while (reader.Read()) constraints.Add(reader.GetString("constraint_name").Trim()); } foreach (var constraint in constraints) { // SQL may need "[dbo].[table]" ExecuteNonQuery("alter table [" + table + "] drop constraint [" + constraint + "]"); } } // drop tables tables = new List(); using (var reader = ExecuteReader("select table_name from information_schema.tables where table_type <> 'VIEW' order by table_name")) { while (reader.Read()) tables.Add(reader.GetString("table_name").Trim()); } foreach (var table in tables) { ExecuteNonQuery("drop table [" + table + "]"); } } } /// /// Drops all foreign keys on a table. /// /// The name of the table. /// To be used in unit tests. internal void DropForeignKeys(string table) { var constraints = new List(); using (var reader = ExecuteReader("select constraint_name from information_schema.table_constraints where constraint_type = 'FOREIGN KEY' and table_name = '" + table + "' order by constraint_name")) { while (reader.Read()) constraints.Add(reader.GetString("constraint_name").Trim()); } foreach (var constraint in constraints) { // SQL may need "[dbo].[table]" ExecuteNonQuery("alter table [" + table + "] drop constraint [" + constraint + "]"); } } /// /// Replaces the data directory with a local path. /// /// The path. /// A local path with the resolved 'DataDirectory' mapping. private string ReplaceDataDirectory(string path) { if (!string.IsNullOrWhiteSpace(path) && path.Contains("|DataDirectory|")) { var dataDirectory = AppDomain.CurrentDomain.GetData("DataDirectory") as string; if (!string.IsNullOrEmpty(dataDirectory)) { path = path.Contains(@"|\") ? path.Replace("|DataDirectory|", dataDirectory) : path.Replace("|DataDirectory|", dataDirectory + System.IO.Path.DirectorySeparatorChar); } } return path; } /// /// Creates a new parameter for use with this specific implementation of ISqlHelper. /// /// Name of the parameter. /// Value of the parameter. /// A new parameter of the correct type. /// Abstract factory pattern public override IParameter CreateParameter(string parameterName, object value) { return new SqlCEParameter(parameterName, value); } /// /// Executes a command that returns a single value. /// /// The command text. /// The parameters. /// The return value of the command. protected override object ExecuteScalar(string commandText, SqlCeParameter[] parameters) { #if DEBUG && DebugDataLayer // Log Query Execution Trace.TraceInformation(GetType().Name + " SQL ExecuteScalar: " + commandText); #endif return SqlCeApplicationBlock.ExecuteScalar(ConnectionString, CommandType.Text, commandText, parameters); } /// /// Executes a command and returns the number of rows affected. /// /// The command text. /// The parameters. /// /// The number of rows affected by the command. /// protected override int ExecuteNonQuery(string commandText, SqlCeParameter[] parameters) { #if DEBUG && DebugDataLayer // Log Query Execution Trace.TraceInformation(GetType().Name + " SQL ExecuteNonQuery: " + commandText); #endif return SqlCeApplicationBlock.ExecuteNonQuery(ConnectionString, CommandType.Text, commandText, parameters); } /// /// Executes a command and returns a records reader containing the results. /// /// The command text. /// The parameters. /// /// A data reader containing the results of the command. /// protected override IRecordsReader ExecuteReader(string commandText, SqlCeParameter[] parameters) { #if DEBUG && DebugDataLayer // Log Query Execution Trace.TraceInformation(GetType().Name + " SQL ExecuteReader: " + commandText); #endif return new SqlCeDataReaderHelper(SqlCeApplicationBlock.ExecuteReader(ConnectionString, CommandType.Text, commandText, parameters)); } } }