// Spludlow Software // Copyright © Samuel P. Ludlow 2020 All Rights Reserved // Distributed under the terms of the GNU General Public License version 3 // Distributed WITHOUT ANY WARRANTY; without implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE // https://www.spludlow.co.uk/LICENCE.TXT // The Spludlow logo is a registered trademark of Samuel P. Ludlow and may not be used without permission // v1.14 using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.IO; using System.Data; using System.Data.Common; using System.Data.SqlClient; namespace Spludlow.Data { /// /// MS SQL Server DAL Implimentation - Fully implimented /// public class DALSql : Spludlow.Data.IDAL { private SqlConnection Connection; private SqlTransaction Transaction = null; private string ChangedDatabase = null; private string CurrentDatabaseCache = null; private string CacheKeyPrefix; private Dictionary ConvertDataTypes; private string QuoteOpen = "["; private string QuoteClose = "]"; private int CommandTimeoutSeconds = -1; private List SystemDatabaseNames = new List(new string[] { "master", "tempdb", "model", "msdb", }); public DALSql() { } public DALSql(string connectionString) { this.Initialize(connectionString); } public void Initialize(string connectionString) { if (connectionString == null || connectionString.Length == 0) // For use with utility methods return; if (connectionString.StartsWith("@") == true) connectionString = Spludlow.Config.ConnectionString(connectionString.Substring(1)); // Short hand HOST@DATABSE or HOST (databse will be 'master') if (connectionString.Contains(";") == false) { string host = null; string database = null; int index = connectionString.IndexOf("@"); if (index == -1) { host = connectionString; } else { host = connectionString.Substring(0, index).Trim(); database = connectionString.Substring(index + 1).Trim(); } connectionString = MakeConnectionString(host, database); } this.Connection = new SqlConnection(connectionString); this.CacheKeyPrefix = "DALSql-Schemas-" + this.DataSource() + "-"; this.ConvertDataTypes = new Dictionary(); string[] convertLookups = new string[] { "image varbinary(max)", "ntext nvarchar(max)", "text varchar(max)", "numeric decimal", "smallmoney money", "smalldatetime datetime", "timestamp rowversion", // But still using timestamp in type enum !!! }; foreach (string convertLookup in convertLookups) { string[] words = Spludlow.Text.Split(convertLookup, '\t', true, false); this.ConvertDataTypes.Add(words[0], words[1]); } this.ChangeDatabase(null); } public static string MakeConnectionString(string host, string database) { return MakeConnectionString(host, database, null, null); } public static string MakeConnectionString(string host, string database, string userName, string password) { string[] names = new string[] { "Data Source", "Initial Catalog", "User ID", "Password" }; string[] values = new string[] { host, database, userName, password }; StringBuilder connectionString = new StringBuilder(); for (int index = 0; index < values.Length; ++index) { string value = values[index]; if (value == null) continue; connectionString.Append(names[index]); connectionString.Append("='"); connectionString.Append(value); connectionString.Append("';"); } if (userName == null) connectionString.Append("Integrated Security=True;"); return connectionString.ToString(); } private void Open() { this.Connection.Open(); if (this.ChangedDatabase != null) { try { string database = this.ChangedDatabase; if (database == "") database = "master"; this.Connection.ChangeDatabase(database); } catch { this.Connection.Close(); throw; } } } private void Close() { this.Connection.Close(); } public string DataSource() { return this.Connection.DataSource; } public void CommandTimeout(int minutes) { if (minutes < 0) this.CommandTimeoutSeconds = -1; else this.CommandTimeoutSeconds = minutes * 60; } // // Current // public string CurrentDatabase() { return this.CurrentDatabaseCache; } public void ChangeDatabase(string databaseName) { this.ChangedDatabase = databaseName; databaseName = (string)this.ExecuteScalar("SELECT DB_NAME();"); if (databaseName == "master") databaseName = null; this.CurrentDatabaseCache = databaseName; } // // Transactions // public void Begin() { if (this.Transaction != null) throw new ApplicationException("DALSql: Begin Transaction already present."); this.Open(); try { this.Transaction = this.Connection.BeginTransaction(); } catch { this.Close(); throw; } } public void Commit() { if (this.Transaction == null) throw new ApplicationException("DALSql: Commit Transaction not present."); try { this.Transaction.Commit(); this.Transaction = null; } finally { this.Close(); } } public void Rollback() { if (this.Transaction == null) throw new ApplicationException("DALSql: Rollback Transaction not present."); try { this.Transaction.Rollback(); this.Transaction = null; } finally { this.Close(); } } // // Schema // public void SchemaRefresh() { string databaseName = this.CurrentDatabase(); if (databaseName == null) throw new ApplicationException("DALSql; To Refresh the schema you must have a current database"); string key = this.CacheKeyPrefix + databaseName; Spludlow.Caching.Remove(key); } public DataSet Schema() { string databaseName = this.CurrentDatabase(); if (databaseName == null) throw new ApplicationException("DALSql; To get the schema you must have a current database"); string key = this.CacheKeyPrefix + databaseName; DataSet schema = (DataSet)Spludlow.Caching.Get(key); if (schema != null) return schema; schema = new DataSet(); DataSet schemaReader = this.SchemaReader(); DataSet schemaNative = this.SchemaNative(); foreach (string fullTableName in this.TableList()) { string[] schemaTableName = DALCommon.SplitSchemaTableName(fullTableName); string schemaName = schemaTableName[0]; if (schemaName == null) schemaName = "dbo"; string tableName = schemaTableName[1]; DataRow nativeSchemaRow = schemaNative.Tables["schemas"].Rows.Find(schemaName); if (nativeSchemaRow == null) throw new ApplicationException("DALSql Schema; Can not find Native schema row: " + schemaName); int schemaId = (int)nativeSchemaRow["schema_id"]; DataRow nativeTableRow = schemaNative.Tables["tables"].Rows.Find(new object[] { tableName, schemaId }); if (nativeTableRow == null) throw new ApplicationException("DALSql Schema; Can not find Native Table row: " + fullTableName); this.SchemaColumns(schema, fullTableName, schemaReader, schemaNative, nativeTableRow); this.SchemaKeys(schema, fullTableName, schemaReader, schemaNative, nativeTableRow); } Spludlow.Caching.Set(key, schema); return schema; } public DataSet Schema(string tableName) { return this.Schema(new string[] { tableName }); } public DataSet Schema(string[] tableNames) { DataSet fullSchema = this.Schema(); DataSet partSchema = new DataSet(); foreach (string tableName in tableNames) { foreach (string suffix in new string[] { "_Columns", "_Keys" }) partSchema.Tables.Add(fullSchema.Tables[tableName + suffix].Copy()); } return partSchema; } private void SchemaColumns(DataSet schema, string fullTableName, DataSet schemaReader, DataSet schemaNative, DataRow nativeTableRow) { DataTable schemaTable = Spludlow.Data.Schemas.NewSchemaColumnsTable(fullTableName); int tableObjectId = (int)nativeTableRow["object_id"]; foreach (DataRow readerRow in schemaReader.Tables[fullTableName].Rows) { string columnName = (string)readerRow["ColumnName"]; DataRow nativeRow = schemaNative.Tables["columns"].Rows.Find(new object[] { tableObjectId, columnName }); if (nativeRow == null) throw new ApplicationException("DALSql Schema; Can not find Native Schema row for column: " + fullTableName + "." + columnName); string typeName = (string)readerRow["DataTypeName"]; if (this.ConvertDataTypes.ContainsKey(typeName) == true) typeName = this.ConvertDataTypes[typeName]; int columnSize = (int)readerRow["ColumnSize"]; if (columnSize == 0x7FFFFFFF && (typeName == "varbinary" || typeName == "nvarchar" || typeName == "varchar")) { typeName += "(max)"; } int index = typeName.LastIndexOf("."); if (index != -1) typeName = typeName.Substring(index + 1); DataRow schemaRow = schemaTable.NewRow(); schemaRow["ColumnName"] = columnName; schemaRow["Ordinal"] = (int)readerRow["ColumnOrdinal"]; schemaRow["DataTypeId"] = Spludlow.Data.Schemas.NativeToCommon(typeName, "SQL"); schemaRow["MaxLength"] = columnSize; schemaRow["Precision"] = (int)((Int16)readerRow["NumericPrecision"]); schemaRow["Scale"] = (int)((Int16)readerRow["NumericScale"]); schemaRow["PrimaryKey"] = (bool)readerRow["IsKey"]; schemaRow["AllowDBNull"] = (bool)readerRow["AllowDBNull"]; schemaRow["AutoIncrement"] = (bool)readerRow["IsAutoIncrement"]; schemaRow["Longest"] = 0; schemaTable.Rows.Add(schemaRow); } Spludlow.Data.Schemas.TidySchemaTable(schemaTable); schema.Tables.Add(schemaTable); } private void SchemaKeys(DataSet schema, string fullTableName, DataSet schemaReader, DataSet schemaNative, DataRow nativeTableRow) { DataTable keysTable = Spludlow.Data.Schemas.NewSchemaKeysTable(fullTableName); DataRow[] rows; int object_id = (int)nativeTableRow["object_id"]; foreach (DataRow indexRow in schemaNative.Tables["indexes"].Select("object_id = " + object_id)) { string indexTypeDesc = (string)indexRow["type_desc"]; if (indexTypeDesc == "HEAP") continue; string keyType; if (indexTypeDesc == "XML") { keyType = "X"; } else { keyType = "I"; if ((bool)indexRow["is_primary_key"] == true) { keyType = "P"; } else { if ((bool)indexRow["is_unique"] == true || (bool)indexRow["is_unique_constraint"] == true) keyType = "U"; } } int index_id = (int)indexRow["index_id"]; string indexName = (string)indexRow["name"]; foreach (DataRow indexColumnRow in schemaNative.Tables["index_columns"].Select("object_id = " + object_id + " AND index_id = " + index_id + "")) { int column_id = (int)indexColumnRow["column_id"]; rows = schemaNative.Tables["columns"].Select("object_id = " + object_id + " AND column_id = " + column_id); if (rows.Length != 1) throw new ApplicationException("DAL SchemaKeys; columns row not found"); string columnName = (string)rows[0]["name"]; int key_ordinal = (int)((byte)indexColumnRow["key_ordinal"]); bool is_descending_key = (bool)indexColumnRow["is_descending_key"]; Spludlow.SysTables.SchemaKeysRow keyRow = (Spludlow.SysTables.SchemaKeysRow)keysTable.Rows.Add(new object[] { indexName, keyType, key_ordinal, is_descending_key, columnName, null, null }); if (keyType == "X") { DataRow xmlIndexRow = schemaNative.Tables["xml_indexes"].Rows.Find(new object[] { object_id, index_id }); if (xmlIndexRow == null) throw new ApplicationException("DAL SchemaKeys; Can not find xml index row indexname:" + indexName); // Is a secondary XML Index if (xmlIndexRow.IsNull("secondary_type_desc") == false) { DataRow xmlPrimaryIndexRow = schemaNative.Tables["xml_indexes"].Rows.Find(new object[] { object_id, (int)xmlIndexRow["using_xml_index_id"] }); keyRow.ParentTable = (string)xmlPrimaryIndexRow["name"]; keyRow.ParentColumn = (string)xmlIndexRow["secondary_type_desc"]; } } } } // Full text indexes DataRow fullTextIndexRow = schemaNative.Tables["fulltext_indexes"].Rows.Find(object_id); if (fullTextIndexRow != null) { int unique_index_id = (int)fullTextIndexRow["unique_index_id"]; int fulltext_catalog_id = (int)fullTextIndexRow["fulltext_catalog_id"]; rows = schemaNative.Tables["indexes"].Select("object_id = " + object_id + " AND index_id = " + unique_index_id); if (rows.Length != 1) throw new ApplicationException("DAL SchemaKeys; text index unique_index_id row not found"); string uniqueIndexName = (string)rows[0]["name"]; DataRow catalogRow = schemaNative.Tables["fulltext_catalogs"].Rows.Find(fulltext_catalog_id); if (catalogRow == null) throw new ApplicationException("DAL SchemaKeys; fulltext_catalogs row not found fulltext_catalog_id:" + fulltext_catalog_id); string fulltext_catalogName = (string)catalogRow["name"]; string indexName = "TX_" + fullTableName.Replace(".", "_"); rows = schemaNative.Tables["fulltext_index_columns"].Select("object_id = " + object_id); if (rows.Length == 0) throw new ApplicationException("DAL SchemaKeys; No columsn for full text index object_id:" + object_id); for (int ordinal = 0; ordinal < rows.Length; ++ordinal) { DataRow fulltextIndexColumnRow = rows[ordinal]; int column_id = (int)fulltextIndexColumnRow["column_id"]; DataRow columnRow; columnRow = FindColumnsRow(schemaNative, object_id, column_id); string columnName = (string)columnRow["name"]; string typeColumnName = null; if (fulltextIndexColumnRow.IsNull("type_column_id") == false) { columnRow = FindColumnsRow(schemaNative, object_id, (int)fulltextIndexColumnRow["type_column_id"]); typeColumnName = (string)columnRow["name"]; } keysTable.Rows.Add(new object[] { indexName, "T", ordinal, false, columnName, fulltext_catalogName + "@" + uniqueIndexName, typeColumnName }); } } // Foriegn Keys foreach (DataRow keyRow in schemaNative.Tables["foreign_keys"].Select("parent_object_id = " + object_id)) { string keyName = (string)keyRow["name"]; int constraint_object_id = (int)keyRow["object_id"]; foreach (DataRow keyColumnRow in schemaNative.Tables["foreign_key_columns"].Select("parent_object_id = " + object_id + " AND constraint_object_id = " + constraint_object_id)) { int parent_object_id = (int)keyColumnRow["parent_object_id"]; int parent_column_id = (int)keyColumnRow["parent_column_id"]; rows = schemaNative.Tables["columns"].Select("object_id = " + parent_object_id + " AND column_id = " + parent_column_id); if (rows.Length != 1) throw new ApplicationException("DAL SchemaKeys; columns row not found"); string columnName = (string)rows[0]["name"]; int referenced_object_id = (int)keyColumnRow["referenced_object_id"]; int referenced_column_id = (int)keyColumnRow["referenced_column_id"]; rows = schemaNative.Tables["tables"].Select("object_id = " + referenced_object_id); if (rows.Length != 1) throw new ApplicationException("DAL SchemaKeys; tables row not found"); string parentTable = (string)rows[0]["name"]; int parentTableSchemaId = (int)rows[0]["schema_id"]; string parentTableSchemaName = this.LookupSchemaName(schemaNative.Tables["schemas"], parentTableSchemaId); if (parentTableSchemaName != "dbo") parentTable = parentTableSchemaName + "." + parentTable; rows = schemaNative.Tables["columns"].Select("object_id = " + referenced_object_id + " AND column_id = " + referenced_column_id); if (rows.Length != 1) throw new ApplicationException("DAL SchemaKeys; columns row not found"); string parentColumn = (string)rows[0]["name"]; keysTable.Rows.Add(new object[] { keyName, "F", 0, false, columnName, parentTable, parentColumn }); } } schema.Tables.Add(keysTable); } private DataRow FindColumnsRow(DataSet schemaNative, int object_id, int column_id) { DataRow[] rows = schemaNative.Tables["columns"].Select("object_id = " + object_id + " AND column_id = " + column_id); if (rows.Length != 1) throw new ApplicationException("DAL SchemaKeys, ColumnsRow; Columns row not found object_id:" + object_id + ", column_id:" + column_id + ", row count:" + rows.Length); return rows[0]; } private string LookupSchemaName(DataTable schemasTable, int schema_id) { DataRow[] rows = schemasTable.Select("schema_id = " + schema_id); if (rows.Length != 1) throw new ApplicationException("DAL LookupSchemaName; Did not find 1 row for schema_id: " + schema_id + ", row count:" + rows.Length); return (string)rows[0]["name"]; } public DataSet SchemaNative() // Only on current, automatically from db { string[] systemViews = new string[] { "databases", "schemas", "types", "tables", "columns", "indexes", "index_columns", "xml_indexes", "foreign_keys", "foreign_key_columns", "fulltext_indexes", "fulltext_index_columns", "fulltext_catalogs" }; DataSet dataSet = new DataSet(); foreach (string systemView in systemViews) { this.Fill(dataSet, "SELECT * FROM sys." + systemView); Spludlow.Data.ADO.NameLastTable(dataSet, systemView); } DataTable table; // Provide reverse lookups table = dataSet.Tables["databases"]; table.PrimaryKey = new DataColumn[] { table.Columns["name"] }; table = dataSet.Tables["schemas"]; table.PrimaryKey = new DataColumn[] { table.Columns["name"] }; table = dataSet.Tables["types"]; table.PrimaryKey = new DataColumn[] { table.Columns["system_type_id"], table.Columns["user_type_id"] }; table = dataSet.Tables["tables"]; table.PrimaryKey = new DataColumn[] { table.Columns["name"], table.Columns["schema_id"] }; table = dataSet.Tables["columns"]; table.PrimaryKey = new DataColumn[] { table.Columns["object_id"], table.Columns["name"] }; table = dataSet.Tables["xml_indexes"]; table.PrimaryKey = new DataColumn[] { table.Columns["object_id"], table.Columns["index_id"] }; table = dataSet.Tables["fulltext_indexes"]; table.PrimaryKey = new DataColumn[] { table.Columns["object_id"] }; table = dataSet.Tables["fulltext_catalogs"]; table.PrimaryKey = new DataColumn[] { table.Columns["fulltext_catalog_id"] }; return dataSet; } public DataSet SchemaConnection() { DataSet schema; if (this.Transaction == null) this.Open(); try { schema = Spludlow.Data.DALCommon.SchemaConnection(this.Connection); } finally { if (this.Transaction == null) this.Close(); } DataTable table; table = schema.Tables["Columns"]; table.PrimaryKey = new DataColumn[] { table.Columns["TABLE_NAME"], table.Columns["COLUMN_NAME"] }; // Same in all return schema; } public DataSet SchemaReader() // dont work in transaction { string[] tableNames = this.TableList(); if (this.Transaction == null) this.Open(); try { return Spludlow.Data.DALCommon.SchemaReader(this.Connection, this.Transaction, tableNames, "[", "]"); // something going on ????? } finally { if (this.Transaction == null) this.Close(); } } public DataSet SchemaANSI() { string[] viewNames = new string[] { "CHECK_CONSTRAINTS", "COLUMN_DOMAIN_USAGE", "COLUMN_PRIVILEGES", "COLUMNS", "CONSTRAINT_COLUMN_USAGE", "CONSTRAINT_TABLE_USAGE", "DOMAIN_CONSTRAINTS", "DOMAINS", "KEY_COLUMN_USAGE", "PARAMETERS", "REFERENTIAL_CONSTRAINTS", "ROUTINES", "ROUTINE_COLUMNS", "SCHEMATA", "TABLE_CONSTRAINTS", "TABLE_PRIVILEGES", "TABLES", "VIEW_COLUMN_USAGE", "VIEW_TABLE_USAGE", "VIEWS", }; DataSet dataSet = new DataSet(); foreach (string viewName in viewNames) { DataTable table = this.Select("SELECT * FROM INFORMATION_SCHEMA." + viewName); table.TableName = viewName; dataSet.Tables.Add(table); } return dataSet; } // // Database // public string[] DatabaseList() { DataTable table = this.Select("select name from sys.databases"); List databases = new List(); foreach (DataRow row in table.Rows) { string name = (string)row[0]; if (SystemDatabaseNames.Contains(name) == false) databases.Add(name); } return databases.ToArray(); } public void DatabaseCreate(string databaseName) { this.ExecuteNonQuery("CREATE DATABASE[" + databaseName + "];"); } public void DatabaseCreate(string databaseName, DataSet schema) { Spludlow.Data.DALCommon.DatabaseCreate(this, databaseName, schema); } public void DatabaseDelete(string databaseName) { this.ExecuteNonQuery("ALTER DATABASE [" + databaseName + "] SET SINGLE_USER WITH ROLLBACK IMMEDIATE;"); this.ExecuteNonQuery("DROP DATABASE [" + databaseName + "];"); } public bool DatabaseExists(string databaseName) { object obj = this.ExecuteScalar("SELECT name FROM sys.databases WHERE name = '" + databaseName + "'"); if (obj == null || obj is DBNull) return false; return true; } // // Tables // public string[] TableList() { string database = this.CurrentDatabase(); if (database == null) throw new ApplicationException("DALSql; To list tables you must have a current database"); //DataTable table = this.Select("select name from sys.tables"); DataTable table = this.Select("SELECT sys.tables.name AS TableName, sys.schemas.name as SchemaName FROM sys.tables INNER JOIN sys.schemas ON sys.tables.schema_id = sys.schemas.schema_id"); List tableNames = new List(); foreach (DataRow row in table.Rows) { string name = (string)row[0]; if (name == "sysdiagrams") continue; string schema = (string)row[1]; if (schema != "dbo") name = schema + "." + name; tableNames.Add(name); } return tableNames.ToArray(); } public void TableCreate(string tableName, DataSet schema) { this.TableCreate(tableName, schema.Tables[tableName + "_Columns"], schema.Tables[tableName + "_Keys"]); } public void TableCreate(string tableName, DataTable schemaColumns, DataTable schemaKeys) { // CREATE TABLE [schemaname].[tableName] // CREATE SCHEMA schema_name [ AUTHORIZATION owner_name ] [;] string[] schemaTableName = DALCommon.SplitSchemaTableName(tableName); if (schemaTableName[0] != null) { this.CreateSchema(schemaTableName[0]); tableName = schemaTableName[0] + "]" + "." + "[" + schemaTableName[1]; } string databaseName = this.CurrentDatabase(); if (databaseName == null) throw new ApplicationException("DAL SQL; To create a table you must have a current database"); Spludlow.Data.DALCommon.CreateTableInfo info = new DALCommon.CreateTableInfo(); info.DatabaseType = "SQL"; info.QuoteOpen = this.QuoteOpen; info.QuoteClose = this.QuoteClose; info.AllowNull = "NULL"; info.DontAllowNull = "NOT NULL"; info.Identity = "IDENTITY"; info.ColumnLine = "@ColumnName @DataType @Identity @Null"; info.PrimaryLine = "CONSTRAINT @KeyName PRIMARY KEY (@Columns)"; info.UniqueLine = null; // "CONSTRAINT @KeyName UNIQUE (@Columns)"; info.ForeignLine = null; // "CONSTRAINT @KeyName FOREIGN KEY (@Columns) REFERENCES @ParentTable(@ParentColumns)"; info.IndexLine = null; // "INDEX @KeyName NONCLUSTERED (@Columns)"; string commandText = Spludlow.Data.DALCommon.MakeCreateTableCommandText(tableName, schemaColumns, schemaKeys, info); this.ExecuteNonQuery(commandText); //Spludlow.Log.Report("DAL; Created Table: " + tableName, new object[] { schemaColumns, schemaKeys, commandText }); } private void CreateSchema(string schemaName) { object result = this.ExecuteScalar("SELECT schema_id FROM sys.schemas WHERE name = @SchemaName", new object[] { schemaName }); if (result != null) return; this.ExecuteNonQuery("CREATE SCHEMA [" + schemaName + "] AUTHORIZATION dbo;"); } private void CreateCatalog(string catalogName) { object result = this.ExecuteScalar("SELECT fulltext_catalog_id FROM sys.fulltext_catalogs WHERE name = @SchemaName", new object[] { catalogName }); if (result != null) return; this.ExecuteNonQuery("CREATE FULLTEXT CATALOG [" + catalogName + "]"); } public void TableDelete(string tableName) { // ALTER DATABASE [SpludlowTempCopy] SET SINGLE_USER WITH ROLLBACK IMMEDIATE // Change to master this.ExecuteNonQuery("DROP TABLE [" + tableName + "]"); } public bool TableExists(string tableName) { object obj = this.ExecuteScalar("SELECT name FROM sys.tables WHERE name = '" + tableName + "'"); if (obj == null || obj is DBNull) return false; return true; } public void TableClear(string tableName) { string databaseName = this.CurrentDatabase(); if (databaseName == null) throw new ApplicationException("DAL SQL; To clear a table you must have a current database"); if (Spludlow.Data.Schemas.TableHasForeignReferences(this.Schema(), tableName) == false) this.ExecuteNonQuery("TRUNCATE TABLE [" + tableName + "]"); else this.ExecuteNonQuery("DELETE FROM [" + tableName + "]"); } public void TableAddKeys(DataSet schema, string keyTypesPUIF) { string[] tableNames = Spludlow.Data.Schemas.TableNamesInOrder(schema); this.TableAddKeys(tableNames, schema, keyTypesPUIF); } public void TableAddKeys(string tableName, DataSet schema, string keyTypesPUIF) { this.TableAddKeys(new string[] { tableName }, schema, keyTypesPUIF); } public void TableAddKeys(string[] tableNames, DataSet schema, string keyTypesPUIF) { // Allways @TableName @KeyName @Columns"; string commandTextPrimary = "ALTER TABLE @TableName ADD CONSTRAINT [@KeyName] PRIMARY KEY (@Columns)"; string commandTextUnique = "CREATE UNIQUE INDEX [@KeyName] ON @TableName (@Columns)"; string commandTextIndex = "CREATE INDEX [@KeyName] ON @TableName (@Columns)"; string commandTextForeign = "ALTER TABLE @TableName ADD CONSTRAINT [@KeyName] FOREIGN KEY (@Columns) REFERENCES @ParentTable (@ParentColumns)"; // Add @ParentTable (@ParentColumns) string commandTextXmlPrimary = "CREATE PRIMARY XML INDEX [@KeyName] ON @TableName (@Columns)"; string commandTextXmlSecondary = "CREATE XML INDEX [@KeyName] ON @TableName (@Columns) USING XML INDEX [@XmlPrimaryIndex] FOR @XmlSecondayType"; // Add @XmlPrimaryIndex] @XmlSecondayType string commandTextFullTextIndex = "CREATE FULLTEXT INDEX ON @TableName (@Columns) KEY INDEX [@KeyIndex] ON [@Catalog]"; // Add @KeyIndex @Catalog foreach (string fullTableName in tableNames) { foreach (char keyType in keyTypesPUIF) { DataTable keysTable = schema.Tables[fullTableName + "_Keys"]; List keyNames = new List(); foreach (DataRow schemaKeyRow in keysTable.Select("KeyType = '" + keyType + "'")) { string keyName = (string)schemaKeyRow["KeyName"]; if (keyNames.Contains(keyName) == false) keyNames.Add(keyName); } foreach (string keyName in keyNames) { Spludlow.SysTables.SchemaKeysRow[] keyRows = (Spludlow.SysTables.SchemaKeysRow[])keysTable.Select("KeyName = '" + keyName + "'"); StringBuilder commandText = new StringBuilder(); switch (keyType) { case 'P': commandText.Append(commandTextPrimary); break; case 'U': commandText.Append(commandTextUnique); break; case 'I': commandText.Append(commandTextIndex); break; case 'X': if (keyRows[0].IsParentTableNull() == true) commandText.Append(commandTextXmlPrimary); else commandText.Append(commandTextXmlSecondary); break; case 'F': commandText.Append(commandTextForeign); break; case 'T': commandText.Append(commandTextFullTextIndex); break; } if (commandText.Length == 0) { Spludlow.Log.Warning("TableAddKeys: Keytype not supported: " + keyType); continue; } commandText.Replace("@KeyName", keyName); commandText.Replace("@TableName", DALCommon.QuoteTableName(fullTableName, this.QuoteOpen, this.QuoteClose)); if (keyType != 'T') commandText.Replace("@Columns", DALCommon.ColumnNames(keyRows, "ColumnName", this.QuoteOpen, this.QuoteClose)); else commandText.Replace("@Columns", this.TextIndexColumnNames(keyRows, this.QuoteOpen, this.QuoteClose)); if (keyType == 'F') { commandText.Replace("@ParentTable", DALCommon.QuoteTableName(keyRows[0].ParentTable, this.QuoteOpen, this.QuoteClose)); commandText.Replace("@ParentColumns", DALCommon.ColumnNames(keyRows, "ParentColumn", this.QuoteOpen, this.QuoteClose)); } if (keyType == 'X') { if (keyRows[0].IsParentTableNull() == false) { commandText.Replace("@XmlPrimaryIndex", keyRows[0].ParentTable); commandText.Replace("@XmlSecondayType", keyRows[0].ParentColumn); } } if (keyType == 'T') { string[] catalogAndKeyIndex = keyRows[0].ParentTable.Split(new char[] { '@' }); if (catalogAndKeyIndex.Length != 2) throw new ApplicationException("DAL SQL TableAddKeys; bad catalogAndKeyIndex :" + catalogAndKeyIndex); string catalogName = catalogAndKeyIndex[0]; string keyIndex = catalogAndKeyIndex[1]; this.CreateCatalog(catalogName); commandText.Replace("@Catalog", catalogName); commandText.Replace("@KeyIndex", keyIndex); Spludlow.Log.Warning(commandText.ToString()); } this.ExecuteNonQuery(commandText.ToString()); } } } } private string TextIndexColumnNames(DataRow[] keyColumns, string quoteOpen, string quoteClose) { StringBuilder tempText = new StringBuilder(); foreach (DataRow keyColumn in keyColumns) { if (tempText.Length > 0) tempText.Append(", "); tempText.Append(quoteOpen); tempText.Append((string)keyColumn["ColumnName"]); tempText.Append(quoteClose); if (keyColumn.IsNull("ParentColumn") == false) { tempText.Append(" TYPE COLUMN "); tempText.Append(quoteOpen); tempText.Append((string)keyColumn["ParentColumn"]); tempText.Append(quoteClose); } } return tempText.ToString(); } // // Logins // public string[] LoginList() // Will conatin '\' is windows otherwise SQL login { DataTable table = this.Select("select name from sys.server_principals WHERE (type <> 'R')"); // or "name" may be problem if renamed ??????? List loginnames = new List(); foreach (DataRow row in table.Rows) { string name = (string)row[0]; if (name.StartsWith("#") == true) continue; loginnames.Add(name); } return loginnames.ToArray(); } public void LoginCreate(string loginName, bool administrator) // Can only use paramters on SQL command not data defintion commands!!! { LoginCreate(loginName, null, administrator); } public void LoginCreate(string loginName, string password, bool administrator) { string commandText; if (password == null) { commandText = "CREATE LOGIN [@LoginName] FROM WINDOWS"; } else { commandText = "CREATE LOGIN [@LoginName] WITH PASSWORD='@Password'"; commandText = commandText.Replace("@Password", password); } commandText = commandText.Replace("@LoginName", loginName); this.ExecuteNonQuery(commandText); if (administrator == true) { commandText = "ALTER SERVER ROLE sysadmin ADD MEMBER [@LoginName]"; commandText = commandText.Replace("@LoginName", loginName); this.ExecuteNonQuery(commandText); } } public void LoginDelete(string loginName) { string commandText = "DROP LOGIN [@LoginName]"; commandText = commandText.Replace("@LoginName", loginName); this.ExecuteNonQuery(commandText); } public bool LoginExists(string loginName) { object result = this.ExecuteScalar("select name from sys.server_principals WHERE (name = @LoginName)", new string[] { "@LoginName" }, new object[] { loginName }); if (result == null || result is DBNull) return false; return true; } // // Users latest is sys.database_principals // public string[] UserList() { string databaseName = this.CurrentDatabase(); if (databaseName == null) throw new ApplicationException("DAL SQL; To List Users you must have a current database"); DataTable table = this.Select("SELECT name FROM sys.database_principals WHERE type <> 'R'"); List userNames = new List(); foreach (DataRow row in table.Rows) { string name = (string)row[0]; userNames.Add(name); } return userNames.ToArray(); } public void UserCreate(string userName, string loginName, bool administrator) { string commandText; commandText = "CREATE USER [@UserName] FOR LOGIN [@LoginName]"; commandText = commandText.Replace("@UserName", userName); commandText = commandText.Replace("@LoginName", loginName); this.ExecuteNonQuery(commandText); string[] roles; if (administrator == true) roles = new string[] { "db_owner" }; else roles = new string[] { "db_datareader", "db_datawriter" }; foreach (string role in roles) { commandText = "ALTER ROLE [@Role] ADD MEMBER [@UserName]"; commandText = commandText.Replace("@Role", role); commandText = commandText.Replace("@UserName", userName); this.ExecuteNonQuery(commandText); } } public void UserDelete(string userName) { string commandText = "DROP USER [@UserName]"; commandText = commandText.Replace("@UserName", userName); this.ExecuteNonQuery(commandText); } public bool UserExists(string userName) { object result = this.ExecuteScalar("select name from sys.database_principals WHERE (name = @UserName)", new string[] { "@UserName" }, new object[] { userName }); if (result == null || result is DBNull) return false; return true; } // // Backup, Restore, Script, Operation // public void Backup(string serverFilename) { string databaseName = this.CurrentDatabase(); if (databaseName == null) throw new ApplicationException("DAL SQL; To backup a database you must have a current database"); string commandText = "BACKUP DATABASE @BackupDatabase TO DISK=@BackupFilename WITH NO_COMPRESSION, INIT, SKIP, NAME=@BackupName"; string backupName = databaseName + "-Full Database Backup"; SqlCommand command = (SqlCommand)this.MakeCommand(commandText, new string[] { "@BackupDatabase", "@BackupFilename", "@BackupName" }, new string[] { databaseName, serverFilename, backupName }); // The time in seconds to wait for the command to execute. The default is 30 seconds. command.CommandTimeout = 30 * 60; // 30 mins this.ExecuteNonQuery(command); } public void Restore(string serverFilename) // Only supports 1 data file !!!!!!!!!!!!!! { string databaseName = this.CurrentDatabase(); if (databaseName == null) throw new ApplicationException("DAL SQL; To restore a database you must have a current database"); DataRow[] rows; DataTable existingFiles = this.Select("SELECT * FROM sys.database_files"); rows = existingFiles.Select("type_desc = 'ROWS'"); if (rows.Length != 1) throw new ApplicationException("DAL SQL Restore; Did not find 1 data file in database: " + databaseName + ", " + rows.Length); string dataPath = (string)rows[0]["physical_name"]; rows = existingFiles.Select("type_desc = 'LOG'"); if (rows.Length != 1) throw new ApplicationException("DAL SQL Restore; Did not find 1 log data file in database: " + databaseName + ", " + rows.Length); string logPath = (string)rows[0]["physical_name"]; dataPath = Path.GetDirectoryName(dataPath) + @"\" + databaseName + ".mdf"; logPath = Path.GetDirectoryName(logPath) + @"\" + databaseName + "_log.ldf"; DataTable backupFileList = this.Select(@"RESTORE FILELISTONLY FROM DISK=@BackupFilename", new string[] { "@BackupFilename" }, new object[] { serverFilename }); rows = backupFileList.Select("Type = 'D'"); if (rows.Length != 1) throw new ApplicationException("DAL SQL Restore; Did not find 1 data file in backup file: " + serverFilename + ", " + rows.Length); string dataName = (string)rows[0]["LogicalName"]; rows = backupFileList.Select("Type = 'L'"); if (rows.Length != 1) throw new ApplicationException("DAL SQL Restore; Did not find 1 log data file in backup file: " + serverFilename + ", " + rows.Length); string logName = (string)rows[0]["LogicalName"]; string commandText = "RESTORE DATABASE @ResotreDatabase FROM DISK=@ResotreFilename WITH REPLACE, MOVE @DataName TO @DataFilename, MOVE @LogName TO @LogFilename"; string[] parameterNames = new string[] { "@ResotreDatabase", "@ResotreFilename", "@DataName", "@DataFilename", "@LogName", "@LogFilename" }; object[] parameterValues = new object[] { databaseName, serverFilename, dataName, dataPath, logName, logPath }; SqlCommand command = (SqlCommand)this.MakeCommand(commandText, parameterNames, parameterValues); command.CommandTimeout = 30 * 60; // 30 mins this.ChangeDatabase(""); this.ExecuteNonQuery(command); this.ChangeDatabase(databaseName); } private string ScriptProgramPath = null; public string RunScript(string localFilename, string server, string database) { return RunScript(localFilename, server, database, null, null); } public string RunScript(string localFilename, string server, string database, string userName, string password) // Utility method not using any object varibles, can use with null constructor { string configKey = "Spludlow.ScriptProgramPath.Sql"; // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! NAME ????? find bin path if (this.ScriptProgramPath == null) this.ScriptProgramPath = Spludlow.Config.Get(configKey, true); if (this.ScriptProgramPath == null) this.ScriptProgramPath = Spludlow.SpawnProcess.FindPath("sqlcmd.exe"); if (this.ScriptProgramPath == null) throw new ApplicationException("DAL SQL; Can not find sqlcmd.exe in the path. You can set the full path to it in an application varible: '" + configKey + "'"); List argumentNames = new List(new string[] { "-S", "-d", "-i" }); if (userName != null) argumentNames.AddRange(new string[] { "-U", "-P" }); string[] argValues = new string[] { server, database, localFilename, userName, password }; StringBuilder arguments = new StringBuilder(); for (int index = 0; index < argumentNames.Count; ++index) { if (arguments.Length > 0) arguments.Append(" "); arguments.Append(argumentNames[index]); arguments.Append(" \""); arguments.Append(argValues[index]); arguments.Append("\""); } string argumentsText = arguments.ToString(); Spludlow.Log.Info("DAL SQL; Running Script: " + this.ScriptProgramPath + " " + argumentsText); Spludlow.SpawnProcess.ProcessExitInfo exitInfo = Spludlow.SpawnProcess.Run(this.ScriptProgramPath, argumentsText, 10 * 60); // 10 mins if (exitInfo.StandardError.Length > 0) Spludlow.Log.Error("DAL SQL; RunScript, Error in output", exitInfo.StandardError); if (exitInfo.ExitCode != 0) throw new ApplicationException("DAL SQL; RunScript, Bad Exit Code: " + exitInfo.ExitCode); return exitInfo.StandardOutput; } public void Operation(string details) { if (details.StartsWith("identity insert") == true) { StringBuilder commandText = new StringBuilder(); commandText.Append("SET IDENTITY_INSERT ["); commandText.Append(details.Substring(16)); commandText.Append("] ON"); this.ExecuteNonQuery(commandText.ToString()); return; } if (details.StartsWith("shrink") == true) { string databaseName = this.CurrentDatabase(); if (databaseName == null) throw new ApplicationException("DAL SQL; To perform a shrink Operation you must have a current database"); if (details == "shrink data") this.ShrinkFile(databaseName, "ROWS", 1); if (details == "shrink log") this.ShrinkFile(databaseName, "LOG", 1); return; } throw new ApplicationException("DAL SQL Operation; Unknown: " + details); } private void ShrinkFile(string databaseName, string fileType, int targetMegabytes) { DataTable existingFiles = this.Select("SELECT * FROM sys.database_files"); Spludlow.Log.Info("DAL SQL ShrinkFile; Stating database:" + databaseName + ", type:" + fileType, new object[] { existingFiles }); DataRow[] rows; // Can do more than 1 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! rows = existingFiles.Select("type_desc = '" + fileType + "'"); if (rows.Length != 1) throw new ApplicationException("DAL SQL Restore; Did not find 1 data file in database: " + databaseName + ", " + fileType + ", " + rows.Length); string logicalName = (string)rows[0]["name"]; string commandText = "DBCC SHRINKFILE (" + logicalName + ", " + targetMegabytes + ")"; DataTable result; this.CommandTimeout(60); this.ExecuteNonQuery("ALTER DATABASE [" + databaseName + "] SET RECOVERY SIMPLE"); try { result = this.Select(commandText); } finally { this.ExecuteNonQuery("ALTER DATABASE [" + databaseName + "] SET RECOVERY FULL"); this.CommandTimeout(-1); } Spludlow.Log.Report("DAL SQL ShrinkFile; Finished database:" + databaseName, new object[] { result }); } public string PageCommandText(string commandText, int pageIndex, int pageSize) { int offset = pageIndex * pageSize; StringBuilder text = new StringBuilder(commandText); text.Append(" OFFSET @Offset ROWS FETCH NEXT @PageSize ROWS ONLY"); text.Replace("@Offset", offset.ToString()); text.Replace("@PageSize", pageSize.ToString()); return text.ToString(); } // // Make Commands // private void SetDataType(DAL.CommandInfo info, DataRow columnRow, int index) { string dataTypeId = (string)columnRow["DataTypeId"]; string nativeType = Spludlow.Data.Schemas.CommonToNative(dataTypeId, "SqlDbType"); int removeIndex = nativeType.IndexOf("("); if (removeIndex != -1) nativeType = nativeType.Substring(0, removeIndex); SqlDbType sqlDbType = (SqlDbType)Enum.Parse(typeof(SqlDbType), nativeType); info.ParameterTypes[index] = (int)sqlDbType; info.ParameterMaxLengths[index] = (int)columnRow["MaxLength"]; } private SqlCommand MakeCommandNative(string commandText) { SqlCommand command = new SqlCommand(commandText, this.Connection, this.Transaction); if (this.CommandTimeoutSeconds >= 0) command.CommandTimeout = this.CommandTimeoutSeconds; return command; } public DAL.CommandInfo MakeCommandInfo(string commandText) { return MakeCommandInfo(commandText, DALCommon.ExtractParameterNames(commandText)); } public DAL.CommandInfo MakeCommandInfo(string commandText, string[] parameterNames) { return Spludlow.Data.DALCommon.MakeCommandInfo(commandText, parameterNames, this.Schema(), this.SetDataType); } public DbCommand MakeCommand(string commandText) { SqlCommand command = this.MakeCommandNative(commandText); return command; } public DbCommand MakeCommand(string commandText, object[] parameterValues) { DAL.CommandInfo commandInfo = this.MakeCommandInfo(commandText); return this.MakeCommand(commandInfo, parameterValues); } public DbCommand MakeCommand(string commandText, string[] parameterNames, object[] parameterValues) { DAL.CommandInfo commandInfo = this.MakeCommandInfo(commandText, parameterNames); return this.MakeCommand(commandInfo, parameterValues); } public DbCommand MakeCommand(DAL.CommandInfo commandInfo, object[] parameterValues) { if (commandInfo.ParameterNames.Length != parameterValues.Length) throw new ApplicationException("Making Command with different parameterNames and parameterValues counts: " + commandInfo.ParameterNames.Length + ", " + parameterValues.Length); SqlCommand command = this.MakeCommandNative(commandInfo.CommandText); for (int index = 0; index < commandInfo.ParameterNames.Length; ++index) { string paramterName = commandInfo.ParameterNames[index]; SqlDbType dbType = (SqlDbType)commandInfo.ParameterTypes[index]; int maxLength = commandInfo.ParameterMaxLengths[index]; SqlParameter parameter = command.CreateParameter(); parameter.ParameterName = paramterName; if ((int)dbType != -1) parameter.SqlDbType = dbType; // seems to make slightly slower ?????????? try differnt DALs parameter.Value = parameterValues[index]; command.Parameters.Add(parameter); } return command; } // // ExecuteScalar // public object ExecuteScalar(string commandText) { using (SqlCommand command = (SqlCommand)this.MakeCommand(commandText)) return this.ExecuteScalar(command); } public object ExecuteScalar(string commandText, object[] parameterValues) { using (SqlCommand command = (SqlCommand)this.MakeCommand(commandText, parameterValues)) return this.ExecuteScalar(command); } public object ExecuteScalar(string commandText, string[] parameterNames, object[] parameterValues) { using (SqlCommand command = (SqlCommand)this.MakeCommand(commandText, parameterNames, parameterValues)) return this.ExecuteScalar(command); } public object ExecuteScalar(DAL.CommandInfo commandInfo, object[] parameterValues) { using (SqlCommand command = (SqlCommand)this.MakeCommand(commandInfo, parameterValues)) return this.ExecuteScalar(command); } public object ExecuteScalar(DbCommand command) { return this.ExecuteScalar((SqlCommand)command); } private object ExecuteScalar(SqlCommand command) { if (this.Transaction != null) return command.ExecuteScalar(); this.Open(); try { return command.ExecuteScalar(); } finally { this.Close(); } } // // ExecuteNonQuery // public int ExecuteNonQuery(string commandText) { using (SqlCommand command = (SqlCommand)this.MakeCommand(commandText)) return this.ExecuteNonQuery(command); } public int ExecuteNonQuery(string commandText, object[] parameterValues) { using (SqlCommand command = (SqlCommand)this.MakeCommand(commandText, parameterValues)) return this.ExecuteNonQuery(command); } public int ExecuteNonQuery(string commandText, string[] parameterNames, object[] parameterValues) { using (SqlCommand command = (SqlCommand)this.MakeCommand(commandText, parameterNames, parameterValues)) return this.ExecuteNonQuery(command); } public int ExecuteNonQuery(DAL.CommandInfo commandInfo, object[] parameterValues) { using (SqlCommand command = (SqlCommand)this.MakeCommand(commandInfo, parameterValues)) return this.ExecuteNonQuery(command); } public int ExecuteNonQuery(DbCommand command) { return this.ExecuteNonQuery((SqlCommand)command); } private int ExecuteNonQuery(SqlCommand command) { if (this.Transaction != null) return command.ExecuteNonQuery(); this.Open(); try { return command.ExecuteNonQuery(); } finally { this.Close(); } } // // Fill // public void Fill(DataSet dataSet, string commandText) { using (SqlCommand command = (SqlCommand)this.MakeCommand(commandText)) this.Fill(dataSet, command); } public void Fill(DataSet dataSet, string commandText, object[] parameterValues) { using (SqlCommand command = (SqlCommand)this.MakeCommand(commandText, parameterValues)) this.Fill(dataSet, command); } public void Fill(DataSet dataSet, string commandText, string[] parameterNames, object[] parameterValues) { using (SqlCommand command = (SqlCommand)this.MakeCommand(commandText, parameterNames, parameterValues)) this.Fill(dataSet, command); } public void Fill(DataSet dataSet, DAL.CommandInfo commandInfo, object[] parameterValues) { using (SqlCommand command = (SqlCommand)this.MakeCommand(commandInfo, parameterValues)) this.Fill(dataSet, command); } public void Fill(DataSet dataSet, DbCommand command) { this.Fill(dataSet, (SqlCommand)command); } private void Fill(DataSet dataSet, SqlCommand command) { this.ExecuteAdapter(command, dataSet, null); } public void Fill(DataTable table, string commandText) { using (SqlCommand command = (SqlCommand)this.MakeCommand(commandText)) this.Fill(table, command); } public void Fill(DataTable table, string commandText, object[] parameterValues) { using (SqlCommand command = (SqlCommand)this.MakeCommand(commandText, parameterValues)) this.Fill(table, command); } public void Fill(DataTable table, string commandText, string[] parameterNames, object[] parameterValues) { using (SqlCommand command = (SqlCommand)this.MakeCommand(commandText, parameterNames, parameterValues)) this.Fill(table, command); } public void Fill(DataTable table, DAL.CommandInfo commandInfo, object[] parameterValues) { using (SqlCommand command = (SqlCommand)this.MakeCommand(commandInfo, parameterValues)) this.Fill(table, command); } public void Fill(DataTable table, DbCommand command) { this.Fill(table, (SqlCommand)command); } private void Fill(DataTable table, SqlCommand command) { this.ExecuteAdapter(command, null, table); } // // Select // public DataTable Select(string commandText) { using (SqlCommand command = (SqlCommand)this.MakeCommand(commandText)) return this.Select(command); } public DataTable Select(string commandText, object[] parameterValues) { using (SqlCommand command = (SqlCommand)this.MakeCommand(commandText, parameterValues)) return this.Select(command); } public DataTable Select(string commandText, string[] parameterNames, object[] parameterValues) { using (SqlCommand command = (SqlCommand)this.MakeCommand(commandText, parameterNames, parameterValues)) return this.Select(command); } public DataTable Select(DAL.CommandInfo commandInfo, object[] parameterValues) { using (SqlCommand command = (SqlCommand)this.MakeCommand(commandInfo, parameterValues)) return this.Select(command); } public DataTable Select(DbCommand command) { return this.Select((SqlCommand)command); } private DataTable Select(SqlCommand command) { DataSet dataSet = this.SelectDS(command); DataTable table = dataSet.Tables[0]; dataSet.Tables.Remove(table); return table; } public DataSet SelectDS(string commandText) { using (SqlCommand command = (SqlCommand)this.MakeCommand(commandText)) return this.SelectDS(command); } public DataSet SelectDS(string commandText, object[] parameterValues) { using (SqlCommand command = (SqlCommand)this.MakeCommand(commandText, parameterValues)) return this.SelectDS(command); } public DataSet SelectDS(string commandText, string[] parameterNames, object[] parameterValues) { using (SqlCommand command = (SqlCommand)this.MakeCommand(commandText, parameterNames, parameterValues)) return this.SelectDS(command); } public DataSet SelectDS(DAL.CommandInfo commandInfo, object[] parameterValues) { using (SqlCommand command = (SqlCommand)this.MakeCommand(commandInfo, parameterValues)) return this.SelectDS(command); } public DataSet SelectDS(DbCommand command) { return this.SelectDS((SqlCommand)command); } private DataSet SelectDS(SqlCommand command) { DataSet dataSet = new DataSet(); this.ExecuteAdapter(command, dataSet, null); return dataSet; } private void ExecuteAdapter(SqlCommand command, DataSet dataSet, DataTable table) { if (this.Transaction == null) this.Open(); try { using (SqlDataAdapter adapter = new SqlDataAdapter(command)) { if (dataSet != null) adapter.Fill(dataSet); if (table != null) adapter.Fill(table); } } finally { if (this.Transaction == null) this.Close(); } } private int NativeIntDataType(DataRow columnRow) { string dataTypeId = (string)columnRow["DataTypeId"]; string nativeType = Spludlow.Data.Schemas.CommonToNative(dataTypeId, "SqlDbType"); int index = nativeType.IndexOf("("); // Fix (max) types if (index != -1) nativeType = nativeType.Substring(0, index); SqlDbType sqlDbType = (SqlDbType)Enum.Parse(typeof(SqlDbType), nativeType); return (int)sqlDbType; } // // Inserter // public DAL.CommandInfo MakeInserter(string tableName) { return DALCommon.MakeInserter(this, tableName, "; SELECT SCOPE_IDENTITY() AS [SCOPE_IDENTITY]"); } public long Insert(DataRow row) { return Insert(row.Table.TableName, row); } public long Insert(string tableName, DataRow row) { DAL.CommandInfo insertInfo = this.MakeInserter(tableName); return Insert(insertInfo, row); } public long Insert(DAL.CommandInfo insertInfo, DataRow row) { object[] objectRow = DALCommon.ObjectsFromRow(row, insertInfo); return Insert(insertInfo, objectRow); } public long Insert(string tableName, object[] row) { DAL.CommandInfo insertInfo = this.MakeInserter(tableName); return Insert(insertInfo, row); } public long Insert(DAL.CommandInfo insertInfo, object[] row) { using (SqlCommand command = (SqlCommand)this.MakeCommand(insertInfo, row)) { if (insertInfo.Identity == false) { this.ExecuteNonQuery(command); return 0; } else { object obj = this.ExecuteScalar(command); if (obj == null) throw new ApplicationException("DAL Insert; Identity object is null."); if (obj is Decimal) return (long)((Decimal)obj); throw new ApplicationException("DAL Insert; Identity object bad type:\t" + obj.GetType().Name); } } } // // Update // public DAL.CommandInfo MakeUpdater(string tableName) { return MakeUpdater(tableName, new string[0]); } public DAL.CommandInfo MakeUpdater(string tableName, string[] updateColumns) { return DALCommon.MakeUpdater(this, this.Schema(), tableName, updateColumns); } public int Update(DataRow row) { return this.Update(row.Table.TableName, row); } public int Update(string tableName, DataRow row) { DAL.CommandInfo updateInfo = this.MakeUpdater(tableName); return this.Update(updateInfo, row); } public int Update(string tableName, string[] columns, DataRow row) { DAL.CommandInfo updateInfo = this.MakeUpdater(tableName, columns); return this.Update(updateInfo, row); } public int Update(DAL.CommandInfo info, DataRow row) { object[] objectRow = DALCommon.ObjectsFromRow(row, info); return this.Update(info, objectRow); } public int Update(string tableName, object[] row) { DAL.CommandInfo updateInfo = this.MakeUpdater(tableName); return this.Update(updateInfo, row); } public int Update(string tableName, string[] columns, object[] row) { DAL.CommandInfo updateInfo = this.MakeUpdater(tableName, columns); return this.Update(updateInfo, row); } public int Update(DAL.CommandInfo updateInfo, object[] row) { using (SqlCommand command = (SqlCommand)this.MakeCommand(updateInfo, row)) { return this.ExecuteNonQuery(command); } } public long InsertOrUpdate(DataRow row) { return this.InsertOrUpdate(row.Table.TableName, row); } public long InsertOrUpdate(string tableName, DataRow row) { DataSet schema = this.Schema(); DataTable columnsTable = schema.Tables[tableName + "_Columns"]; List primaryKeys = new List(); List primaryKeyParams = new List(); foreach (DataRow columnRow in columnsTable.Rows) { if ((bool)columnRow["PrimaryKey"] == false) continue; string keyName = (string)columnRow["ColumnName"]; primaryKeys.Add(keyName); primaryKeyParams.Add("@" + keyName); } if (primaryKeys.Count == 0) throw new ApplicationException("DAL SQL; InsertOrUpdate, table has no primary key: " + tableName); StringBuilder commandText = new StringBuilder("SELECT @FirstKey FROM @TableName WHERE (@Where)"); commandText.Replace("@FirstKey", primaryKeys[0]); commandText.Replace("@TableName", tableName); commandText.Replace("@Where", DALCommon.CommandTextPairs(primaryKeys.ToArray(), " AND ")); object[] keyData = new object[primaryKeys.Count]; for (int index = 0; index < primaryKeys.Count; ++index) keyData[index] = row[primaryKeys[index]]; object result = this.ExecuteScalar(commandText.ToString(), primaryKeyParams.ToArray(), keyData); if (result == null) return this.Insert(tableName, row); this.Update(tableName, row); return 0; } public void BulkInsert(DataTable table, string tableName, string tempDirectory) { this.Open(); try { SqlBulkCopy bulkCopy = new SqlBulkCopy(this.Connection, SqlBulkCopyOptions.KeepIdentity | SqlBulkCopyOptions.KeepNulls, null); bulkCopy.ColumnMappings.Clear(); foreach (DataColumn column in table.Columns) bulkCopy.ColumnMappings.Add(column.ColumnName, column.ColumnName); try { bulkCopy.BulkCopyTimeout = 1 * 60 * 60; bulkCopy.DestinationTableName = "[" + tableName + "]"; bulkCopy.WriteToServer(table); } finally { bulkCopy.Close(); } } finally { this.Close(); } } } }