From 2ea3fe624f7b18e6fb1dd5f688be174a51039125 Mon Sep 17 00:00:00 2001 From: Morten Christensen Date: Wed, 19 Dec 2012 15:23:05 -0100 Subject: [PATCH] Refactoring SqlSyntaProvider to use the new common definitions. --- .../DefinitionFactory.cs | 9 +- .../Persistence/PetaPocoExtensions.cs | 43 +-- .../SqlSyntax/ISqlSyntaxProvider.cs | 21 +- .../SqlSyntax/MySqlSyntaxProvider.cs | 136 +++----- .../SqlSyntax/SqlCeSyntaxProvider.cs | 38 ++- .../SqlSyntax/SqlServerSyntaxProvider.cs | 15 + .../SqlSyntax/SqlSyntaxProviderBase.cs | 315 +++++++----------- .../Persistence/SqlCeTableByTableTest.cs | 2 + .../Persistence/SqlTableByTableTest.cs | 2 + .../SyntaxProvider/SqlSyntaxProviderTests.cs | 46 +++ src/Umbraco.Tests/Umbraco.Tests.csproj | 1 + 11 files changed, 293 insertions(+), 335 deletions(-) create mode 100644 src/Umbraco.Tests/Persistence/SyntaxProvider/SqlSyntaxProviderTests.cs diff --git a/src/Umbraco.Core/Persistence/DatabaseModelDefinitions/DefinitionFactory.cs b/src/Umbraco.Core/Persistence/DatabaseModelDefinitions/DefinitionFactory.cs index b4f328a591..143a4b7fe6 100644 --- a/src/Umbraco.Core/Persistence/DatabaseModelDefinitions/DefinitionFactory.cs +++ b/src/Umbraco.Core/Persistence/DatabaseModelDefinitions/DefinitionFactory.cs @@ -142,10 +142,13 @@ namespace Umbraco.Core.Persistence.DatabaseModelDefinitions IsUnique = attribute.IndexType == IndexTypes.UniqueNonClustered }; - var columns = attribute.ForColumns.Split(',').Select(p => p.Trim()); - foreach (var column in columns) + if (string.IsNullOrEmpty(attribute.ForColumns) == false) { - definition.Columns.Add(new IndexColumnDefinition{Name = column, Direction = Direction.Ascending}); + var columns = attribute.ForColumns.Split(',').Select(p => p.Trim()); + foreach (var column in columns) + { + definition.Columns.Add(new IndexColumnDefinition {Name = column, Direction = Direction.Ascending}); + } } return definition; } diff --git a/src/Umbraco.Core/Persistence/PetaPocoExtensions.cs b/src/Umbraco.Core/Persistence/PetaPocoExtensions.cs index e154cb3fbc..33e6bd76e9 100644 --- a/src/Umbraco.Core/Persistence/PetaPocoExtensions.cs +++ b/src/Umbraco.Core/Persistence/PetaPocoExtensions.cs @@ -1,8 +1,9 @@ using System; +using System.Linq; using Umbraco.Core.Logging; +using Umbraco.Core.Persistence.DatabaseModelDefinitions; using Umbraco.Core.Persistence.Migrations.Initial; using Umbraco.Core.Persistence.SqlSyntax; -using Umbraco.Core.Persistence.SqlSyntax.ModelDefinitions; namespace Umbraco.Core.Persistence { @@ -28,15 +29,13 @@ namespace Umbraco.Core.Persistence public static void CreateTable(this Database db, bool overwrite, Type modelType) { - //TODO The line below should be refactored to use 'Umbraco.Core.Persistence.DatabaseModelDefinitions.DefinitionFactory.GetTableDefinition(modelType)' - //But first the sql syntax provider should be updated/refactored to format sql statements using the 'new' definitions from the DatabaseModelDefinitions-namespace. var tableDefinition = DefinitionFactory.GetTableDefinition(modelType); - var tableName = tableDefinition.TableName; + var tableName = tableDefinition.Name; - string createSql = SyntaxConfig.SqlSyntaxProvider.ToCreateTableStatement(tableDefinition); - string createPrimaryKeySql = SyntaxConfig.SqlSyntaxProvider.ToCreatePrimaryKeyStatement(tableDefinition); - var foreignSql = SyntaxConfig.SqlSyntaxProvider.ToCreateForeignKeyStatements(tableDefinition); - var indexSql = SyntaxConfig.SqlSyntaxProvider.ToCreateIndexStatements(tableDefinition); + string createSql = SyntaxConfig.SqlSyntaxProvider.Format(tableDefinition); + string createPrimaryKeySql = SyntaxConfig.SqlSyntaxProvider.FormatPrimaryKey(tableDefinition); + var foreignSql = SyntaxConfig.SqlSyntaxProvider.Format(tableDefinition.ForeignKeys); + var indexSql = SyntaxConfig.SqlSyntaxProvider.Format(tableDefinition.Indexes); var tableExist = db.TableExist(tableName); if (overwrite && tableExist) @@ -50,10 +49,14 @@ namespace Umbraco.Core.Persistence { //Execute the Create Table sql int created = db.Execute(new Sql(createSql)); + LogHelper.Info(string.Format("Create Table sql {0}:\n {1}", created, createSql)); //If any statements exists for the primary key execute them here if (!string.IsNullOrEmpty(createPrimaryKeySql)) - db.Execute(new Sql(createPrimaryKeySql)); + { + int createdPk = db.Execute(new Sql(createPrimaryKeySql)); + LogHelper.Info(string.Format("Primary Key sql {0}:\n {1}", createdPk, createPrimaryKeySql)); + } //Fires the NewTable event, which is used internally to insert base data before adding constrants to the schema if (NewTable != null) @@ -61,14 +64,14 @@ namespace Umbraco.Core.Persistence var e = new TableCreationEventArgs(); //Turn on identity insert if db provider is not mysql - if (ApplicationContext.Current.DatabaseContext.ProviderName.Contains("MySql") == false && tableDefinition.IsIdentity) + if (ApplicationContext.Current.DatabaseContext.ProviderName.Contains("MySql") == false && tableDefinition.Columns.Any(x => x.IsIdentity)) db.Execute(new Sql(string.Format("SET IDENTITY_INSERT {0} ON ", SyntaxConfig.SqlSyntaxProvider.GetQuotedTableName(tableName)))); //Call the NewTable-event to trigger the insert of base/default data NewTable(tableName, db, e); //Turn off identity insert if db provider is not mysql - if (ApplicationContext.Current.DatabaseContext.ProviderName.Contains("MySql") == false && tableDefinition.IsIdentity) + if (ApplicationContext.Current.DatabaseContext.ProviderName.Contains("MySql") == false && tableDefinition.Columns.Any(x => x.IsIdentity)) db.Execute(new Sql(string.Format("SET IDENTITY_INSERT {0} OFF;", SyntaxConfig.SqlSyntaxProvider.GetQuotedTableName(tableName)))); } @@ -76,23 +79,25 @@ namespace Umbraco.Core.Persistence foreach (var sql in foreignSql) { int createdFk = db.Execute(new Sql(sql)); + LogHelper.Info(string.Format("Create Foreign Key sql {0}:\n {1}", createdFk, sql)); } //Loop through index statements and execute sql foreach (var sql in indexSql) { int createdIndex = db.Execute(new Sql(sql)); + LogHelper.Info(string.Format("Create Index sql {0}:\n {1}", createdIndex, sql)); } //Specific to Sql Ce - look for changes to Identity Seed - if (ApplicationContext.Current.DatabaseContext.ProviderName.Contains("SqlServerCe")) - { - var seedSql = SyntaxConfig.SqlSyntaxProvider.ToAlterIdentitySeedStatements(tableDefinition); - foreach (var sql in seedSql) - { - int createdSeed = db.Execute(new Sql(sql)); - } - } + //if (ApplicationContext.Current.DatabaseContext.ProviderName.Contains("SqlServerCe")) + //{ + // var seedSql = SyntaxConfig.SqlSyntaxProvider.ToAlterIdentitySeedStatements(tableDefinition); + // foreach (var sql in seedSql) + // { + // int createdSeed = db.Execute(new Sql(sql)); + // } + //} transaction.Complete(); } diff --git a/src/Umbraco.Core/Persistence/SqlSyntax/ISqlSyntaxProvider.cs b/src/Umbraco.Core/Persistence/SqlSyntax/ISqlSyntaxProvider.cs index 6930f9d9d8..9eef406cb1 100644 --- a/src/Umbraco.Core/Persistence/SqlSyntax/ISqlSyntaxProvider.cs +++ b/src/Umbraco.Core/Persistence/SqlSyntax/ISqlSyntaxProvider.cs @@ -1,8 +1,6 @@ -using System; using System.Collections.Generic; -using System.Data; using Umbraco.Core.Persistence.DatabaseAnnotations; -using Umbraco.Core.Persistence.SqlSyntax.ModelDefinitions; +using Umbraco.Core.Persistence.DatabaseModelDefinitions; namespace Umbraco.Core.Persistence.SqlSyntax { @@ -15,17 +13,8 @@ namespace Umbraco.Core.Persistence.SqlSyntax string GetQuotedColumnName(string columnName); string GetQuotedName(string name); bool DoesTableExist(Database db, string tableName); - string ToCreateTableStatement(TableDefinition tableDefinition); - List ToCreateForeignKeyStatements(TableDefinition tableDefinition); - List ToCreateIndexStatements(TableDefinition tableDefinition); - DbType GetColumnDbType(Type valueType); string GetIndexType(IndexTypes indexTypes); - string GetColumnDefinition(ColumnDefinition column, string tableName); - string GetPrimaryKeyStatement(ColumnDefinition column, string tableName); - string ToCreatePrimaryKeyStatement(TableDefinition table); string GetSpecialDbType(SpecialDbTypes dbTypes); - string GetConstraintDefinition(ColumnDefinition column, string tableName); - List ToAlterIdentitySeedStatements(TableDefinition table); string CreateTable { get; } string DropTable { get; } string AddColumn { get; } @@ -44,6 +33,12 @@ namespace Umbraco.Core.Persistence.SqlSyntax string CreateConstraint { get; } string DeleteConstraint { get; } string CreateForeignKeyConstraint { get; } - string Format(DatabaseModelDefinitions.ColumnDefinition column); + string Format(TableDefinition table); + string Format(IEnumerable columns); + List Format(IEnumerable indexes); + List Format(IEnumerable foreignKeys); + string FormatPrimaryKey(TableDefinition table); + string GetQuotedValue(string value); + string Format(ColumnDefinition column); } } \ No newline at end of file diff --git a/src/Umbraco.Core/Persistence/SqlSyntax/MySqlSyntaxProvider.cs b/src/Umbraco.Core/Persistence/SqlSyntax/MySqlSyntaxProvider.cs index 3c484a8ebf..edb9f7b9b2 100644 --- a/src/Umbraco.Core/Persistence/SqlSyntax/MySqlSyntaxProvider.cs +++ b/src/Umbraco.Core/Persistence/SqlSyntax/MySqlSyntaxProvider.cs @@ -1,9 +1,6 @@ -using System.Collections.Generic; -using System.Text; +using System.Linq; using Umbraco.Core.Persistence.DatabaseAnnotations; using Umbraco.Core.Persistence.DatabaseModelDefinitions; -using ColumnDefinition = Umbraco.Core.Persistence.SqlSyntax.ModelDefinitions.ColumnDefinition; -using TableDefinition = Umbraco.Core.Persistence.SqlSyntax.ModelDefinitions.TableDefinition; namespace Umbraco.Core.Persistence.SqlSyntax { @@ -67,96 +64,20 @@ namespace Umbraco.Core.Persistence.SqlSyntax return "NVARCHAR"; } - public override string GetConstraintDefinition(ColumnDefinition column, string tableName) + public override string Format(IndexDefinition index) { - var sql = new StringBuilder(); + string name = string.IsNullOrEmpty(index.Name) + ? string.Format("IX_{0}_{1}", index.TableName, index.ColumnName) + : index.Name; - if (column.ConstraintDefaultValue.Equals("getdate()")) - { - sql.Append(" DEFAULT CURRENT_TIMESTAMP"); - } - else - { - sql.AppendFormat(DefaultValueFormat, column.ConstraintDefaultValue); - } + string columns = index.Columns.Any() + ? string.Join(",", index.Columns.Select(x => GetQuotedColumnName(x.Name))) + : GetQuotedColumnName(index.ColumnName); - return sql.ToString(); - } - - public override string GetColumnDefinition(ColumnDefinition column, string tableName) - { - string dbTypeDefinition; - if (column.HasSpecialDbType) - { - if (column.DbTypeLength.HasValue) - { - dbTypeDefinition = string.Format("{0}({1})", - GetSpecialDbType(column.DbType), - column.DbTypeLength.Value); - } - else - { - dbTypeDefinition = GetSpecialDbType(column.DbType); - } - } - else if (column.PropertyType == typeof(string)) - { - dbTypeDefinition = string.Format(StringLengthColumnDefinitionFormat, column.DbTypeLength.GetValueOrDefault(DefaultStringLength)); - } - else - { - if (!DbTypeMap.ColumnTypeMap.TryGetValue(column.PropertyType, out dbTypeDefinition)) - { - dbTypeDefinition = ""; - } - } - - var sql = new StringBuilder(); - sql.AppendFormat("{0} {1}", GetQuotedColumnName(column.ColumnName), dbTypeDefinition); - - if (column.IsPrimaryKeyIdentityColumn) - { - sql.Append(" NOT NULL PRIMARY KEY ").Append(AutoIncrementDefinition); - } - else - { - sql.Append(column.IsNullable ? " NULL" : " NOT NULL"); - } - - if (column.HasConstraint) - { - sql.Append(GetConstraintDefinition(column, tableName)); - sql = sql.Replace("DATETIME", "TIMESTAMP"); - } - - return sql.ToString(); - } - - public override string GetPrimaryKeyStatement(ColumnDefinition column, string tableName) - { - return string.Empty; - } - - public override List ToCreateIndexStatements(TableDefinition table) - { - var indexes = new List(); - - foreach (var index in table.IndexDefinitions) - { - string name = string.IsNullOrEmpty(index.IndexName) - ? string.Format("IX_{0}_{1}", table.TableName, index.IndexForColumn) - : index.IndexName; - - string columns = string.IsNullOrEmpty(index.ColumnNames) - ? GetQuotedColumnName(index.IndexForColumn) - : index.ColumnNames; - - indexes.Add(string.Format("CREATE INDEX {0} ON {1} ({2}); \n", - GetQuotedName(name), - GetQuotedTableName(table.TableName), - columns)); - } - return indexes; + return string.Format(CreateIndex, + GetQuotedName(name), + GetQuotedTableName(index.TableName), + columns); } public override bool DoesTableExist(Database db, string tableName) @@ -170,11 +91,40 @@ namespace Umbraco.Core.Persistence.SqlSyntax return result > 0; } - protected override string FormatIdentity(DatabaseModelDefinitions.ColumnDefinition column) + protected override string FormatIdentity(ColumnDefinition column) { return column.IsIdentity ? AutoIncrementDefinition : string.Empty; } + protected override string FormatDefaultValue(ColumnDefinition column) + { + if (column.DefaultValue == null) + return string.Empty; + + // see if this is for a system method + if (column.DefaultValue is SystemMethods) + { + string method = FormatSystemMethods((SystemMethods)column.DefaultValue); + if (string.IsNullOrEmpty(method)) + return string.Empty; + + return string.Format(DefaultValueFormat, method); + } + + if (column.DefaultValue.ToString().Equals("getdate()")) + return "DEFAULT CURRENT_TIMESTAMP"; + + return string.Format(DefaultValueFormat, column.DefaultValue); + } + + protected override string FormatPrimaryKey(ColumnDefinition column) + { + if(column.IsPrimaryKey) + return "PRIMARY KEY"; + + return string.Empty; + } + protected override string FormatSystemMethods(SystemMethods systemMethod) { switch (systemMethod) @@ -197,5 +147,7 @@ namespace Umbraco.Core.Persistence.SqlSyntax public override string DeleteConstraint { get { return "ALTER TABLE {0} DROP {1}{2}"; } } public override string CreateTable { get { return "CREATE TABLE {0} ({1}) ENGINE = INNODB"; } } + + public override string CreateIndex { get { return "CREATE INDEX {0} ON {1} ({2})"; } } } } \ No newline at end of file diff --git a/src/Umbraco.Core/Persistence/SqlSyntax/SqlCeSyntaxProvider.cs b/src/Umbraco.Core/Persistence/SqlSyntax/SqlCeSyntaxProvider.cs index 13f41903d7..2bcc82b330 100644 --- a/src/Umbraco.Core/Persistence/SqlSyntax/SqlCeSyntaxProvider.cs +++ b/src/Umbraco.Core/Persistence/SqlSyntax/SqlCeSyntaxProvider.cs @@ -1,6 +1,6 @@ -using Umbraco.Core.Persistence.DatabaseAnnotations; +using System.Linq; +using Umbraco.Core.Persistence.DatabaseAnnotations; using Umbraco.Core.Persistence.DatabaseModelDefinitions; -using ColumnDefinition = Umbraco.Core.Persistence.SqlSyntax.ModelDefinitions.ColumnDefinition; namespace Umbraco.Core.Persistence.SqlSyntax { @@ -68,22 +68,25 @@ namespace Umbraco.Core.Persistence.SqlSyntax return string.Format("[{0}]", name); } - public override string GetPrimaryKeyStatement(ColumnDefinition column, string tableName) + public override string FormatPrimaryKey(TableDefinition table) { - string constraintName = string.IsNullOrEmpty(column.PrimaryKeyName) - ? string.Format("PK_{0}", tableName) - : column.PrimaryKeyName; + var columnDefinition = table.Columns.FirstOrDefault(x => x.IsPrimaryKey); + if (columnDefinition == null) + return string.Empty; - string columns = string.IsNullOrEmpty(column.PrimaryKeyColumns) - ? GetQuotedColumnName(column.ColumnName) - : column.PrimaryKeyColumns; + string constraintName = string.IsNullOrEmpty(columnDefinition.PrimaryKeyName) + ? string.Format("PK_{0}", table.Name) + : columnDefinition.PrimaryKeyName; - string sql = string.Format("ALTER TABLE {0} ADD CONSTRAINT {1} PRIMARY KEY ({2}); \n", - GetQuotedTableName(tableName), - GetQuotedName(constraintName), - columns); + string columns = string.IsNullOrEmpty(columnDefinition.PrimaryKeyColumns) + ? GetQuotedColumnName(columnDefinition.Name) + : columnDefinition.PrimaryKeyColumns; - return sql; + return string.Format(CreateConstraint, + GetQuotedTableName(table.Name), + GetQuotedName(constraintName), + "PRIMARY KEY", + columns); } public override bool DoesTableExist(Database db, string tableName) @@ -95,13 +98,16 @@ namespace Umbraco.Core.Persistence.SqlSyntax return result > 0; } - protected override string FormatIdentity(DatabaseModelDefinitions.ColumnDefinition column) + protected override string FormatIdentity(ColumnDefinition column) { return column.IsIdentity ? GetIdentityString(column) : string.Empty; } - private static string GetIdentityString(DatabaseModelDefinitions.ColumnDefinition column) + private static string GetIdentityString(ColumnDefinition column) { + if (column.Seeding != default(int)) + return string.Format("IDENTITY({0},1)", column.Seeding); + return "IDENTITY(1,1)"; } diff --git a/src/Umbraco.Core/Persistence/SqlSyntax/SqlServerSyntaxProvider.cs b/src/Umbraco.Core/Persistence/SqlSyntax/SqlServerSyntaxProvider.cs index 527ad161b6..f0f353840a 100644 --- a/src/Umbraco.Core/Persistence/SqlSyntax/SqlServerSyntaxProvider.cs +++ b/src/Umbraco.Core/Persistence/SqlSyntax/SqlServerSyntaxProvider.cs @@ -34,6 +34,21 @@ namespace Umbraco.Core.Persistence.SqlSyntax InitColumnTypeMap(); } + public override string GetQuotedTableName(string tableName) + { + return string.Format("[{0}]", tableName); + } + + public override string GetQuotedColumnName(string columnName) + { + return string.Format("[{0}]", columnName); + } + + public override string GetQuotedName(string name) + { + return string.Format("[{0}]", name); + } + public override bool DoesTableExist(Database db, string tableName) { var result = diff --git a/src/Umbraco.Core/Persistence/SqlSyntax/SqlSyntaxProviderBase.cs b/src/Umbraco.Core/Persistence/SqlSyntax/SqlSyntaxProviderBase.cs index 5e0bd84f4f..ca1a899e3e 100644 --- a/src/Umbraco.Core/Persistence/SqlSyntax/SqlSyntaxProviderBase.cs +++ b/src/Umbraco.Core/Persistence/SqlSyntax/SqlSyntaxProviderBase.cs @@ -5,8 +5,6 @@ using System.Linq; using System.Text; using Umbraco.Core.Persistence.DatabaseAnnotations; using Umbraco.Core.Persistence.DatabaseModelDefinitions; -using ColumnDefinition = Umbraco.Core.Persistence.SqlSyntax.ModelDefinitions.ColumnDefinition; -using TableDefinition = Umbraco.Core.Persistence.SqlSyntax.ModelDefinitions.TableDefinition; namespace Umbraco.Core.Persistence.SqlSyntax { @@ -22,11 +20,12 @@ namespace Umbraco.Core.Persistence.SqlSyntax { protected SqlSyntaxProviderBase() { - ClauseOrder = new List> + ClauseOrder = new List> { FormatString, FormatType, FormatNullable, + FormatConstraint, FormatDefaultValue, FormatPrimaryKey, FormatIdentity @@ -36,7 +35,7 @@ namespace Umbraco.Core.Persistence.SqlSyntax public string StringLengthNonUnicodeColumnDefinitionFormat = "VARCHAR({0})"; public string StringLengthUnicodeColumnDefinitionFormat = "NVARCHAR({0})"; - public string DefaultValueFormat = " DEFAULT ({0})"; + public string DefaultValueFormat = "DEFAULT ({0})"; public int DefaultStringLength = 255; //Set by Constructor @@ -54,7 +53,7 @@ namespace Umbraco.Core.Persistence.SqlSyntax public string DateTimeColumnDefinition = "DATETIME"; public string TimeColumnDefinition = "DATETIME"; - protected IList> ClauseOrder { get; set; } + protected IList> ClauseOrder { get; set; } protected DbTypes DbTypeMap = new DbTypes(); protected void InitColumnTypeMap() @@ -152,190 +151,91 @@ namespace Umbraco.Core.Persistence.SqlSyntax return "NVARCHAR"; } - public virtual string GetColumnDefinition(ColumnDefinition column, string tableName) - { - string dbTypeDefinition; - if (column.HasSpecialDbType) - { - if (column.DbTypeLength.HasValue) - { - dbTypeDefinition = string.Format("{0}({1})", - GetSpecialDbType(column.DbType), - column.DbTypeLength.Value); - } - else - { - dbTypeDefinition = GetSpecialDbType(column.DbType); - } - } - else if (column.PropertyType == typeof(string)) - { - dbTypeDefinition = string.Format(StringLengthColumnDefinitionFormat, column.DbTypeLength.GetValueOrDefault(DefaultStringLength)); - } - else - { - if (!DbTypeMap.ColumnTypeMap.TryGetValue(column.PropertyType, out dbTypeDefinition)) - { - dbTypeDefinition = ""; - } - } - - var sql = new StringBuilder(); - sql.AppendFormat("{0} {1}", GetQuotedColumnName(column.ColumnName), dbTypeDefinition); - - if (column.IsPrimaryKeyIdentityColumn) - { - sql.Append(" NOT NULL ").Append(AutoIncrementDefinition); - } - else - { - sql.Append(column.IsNullable ? " NULL" : " NOT NULL"); - } - - if(column.HasConstraint) - { - sql.Append(GetConstraintDefinition(column, tableName)); - } - - return sql.ToString(); - } - - public virtual string GetConstraintDefinition(ColumnDefinition column, string tableName) - { - var sql = new StringBuilder(); - sql.AppendFormat(" CONSTRAINT {0}", - string.IsNullOrEmpty(column.ConstraintName) - ? GetQuotedName(string.Format("DF_{0}_{1}", tableName, column.ColumnName)) - : column.ConstraintName); - - string value = column.PropertyType == typeof (string) - ? GetQuotedValue(column.ConstraintDefaultValue) - : column.ConstraintDefaultValue; - - sql.AppendFormat(DefaultValueFormat, value); - return sql.ToString(); - } - - public virtual string GetPrimaryKeyStatement(ColumnDefinition column, string tableName) - { - string constraintName = string.IsNullOrEmpty(column.PrimaryKeyName) - ? string.Format("PK_{0}", tableName) - : column.PrimaryKeyName; - - string columns = string.IsNullOrEmpty(column.PrimaryKeyColumns) - ? GetQuotedColumnName(column.ColumnName) - : column.PrimaryKeyColumns; - - string sql = string.Format("ALTER TABLE {0} ADD CONSTRAINT {1} PRIMARY KEY {2} ({3}); \n", - GetQuotedTableName(tableName), - GetQuotedName(constraintName), - column.IsPrimaryKeyClustered ? "CLUSTERED" : "NONCLUSTERED", - columns); - return sql; - } - - public virtual string ToCreateTableStatement(TableDefinition table) - { - var columns = new StringBuilder(); - - foreach (var column in table.ColumnDefinitions) - { - columns.Append(GetColumnDefinition(column, table.TableName) + ", \n"); - } - - string sql = string.Format("CREATE TABLE {0} \n(\n {1} \n); \n", - table.TableName, - columns.ToString().TrimEnd(", \n".ToCharArray())); - - return sql; - } - - public virtual string ToCreatePrimaryKeyStatement(TableDefinition table) - { - var columnDefinition = table.ColumnDefinitions.FirstOrDefault(x => x.IsPrimaryKey); - if (columnDefinition == null) - return string.Empty; - - var sql = GetPrimaryKeyStatement(columnDefinition, table.TableName); - return sql; - } - - public virtual List ToCreateForeignKeyStatements(TableDefinition table) - { - var foreignKeys = new List(); - - foreach (var key in table.ForeignKeyDefinitions) - { - string constraintName = string.IsNullOrEmpty(key.ConstraintName) - ? string.Format("FK_{0}_{1}_{2}", table.TableName, key.ReferencedTableName, key.ReferencedColumnName) - : key.ConstraintName; - - foreignKeys.Add(string.Format("ALTER TABLE {0} ADD CONSTRAINT {1} FOREIGN KEY ({2}) REFERENCES {3} ({4}); \n", - GetQuotedTableName(table.TableName), - GetQuotedName(constraintName), - GetQuotedColumnName(key.ColumnName), - GetQuotedTableName(key.ReferencedTableName), - GetQuotedColumnName(key.ReferencedColumnName))); - } - - return foreignKeys; - } - - public virtual List ToCreateIndexStatements(TableDefinition table) - { - var indexes = new List(); - - foreach (var index in table.IndexDefinitions) - { - string name = string.IsNullOrEmpty(index.IndexName) - ? string.Format("IX_{0}_{1}", table.TableName, index.IndexForColumn) - : index.IndexName; - - string columns = string.IsNullOrEmpty(index.ColumnNames) - ? GetQuotedColumnName(index.IndexForColumn) - : index.ColumnNames; - - indexes.Add(string.Format("CREATE {0} INDEX {1} ON {2} ({3}); \n", - GetIndexType(index.IndexType), - GetQuotedName(name), - GetQuotedTableName(table.TableName), - columns)); - } - return indexes; - } - - public virtual List ToAlterIdentitySeedStatements(TableDefinition table) - { - var seeds = new List(); - - foreach (var definition in table.ColumnDefinitions) - { - if (definition.PrimaryKeySeeding > 0) - { - seeds.Add(string.Format("ALTER TABLE {0} ALTER COLUMN {1} IDENTITY({2},1); \n", - GetQuotedTableName(table.TableName), - GetQuotedColumnName(definition.ColumnName), - definition.PrimaryKeySeeding)); - } - } - - return seeds; - } - public virtual bool DoesTableExist(Database db, string tableName) { return false; } - public virtual DbType GetColumnDbType(Type valueType) + public virtual string Format(TableDefinition table) { - if (valueType.IsEnum) - return DbTypeMap.ColumnDbTypeMap[typeof(string)]; + var statement = string.Format(CreateTable, table.Name, Format(table.Columns)); - return DbTypeMap.ColumnDbTypeMap[valueType]; + return statement; } - public virtual string Format(DatabaseModelDefinitions.ColumnDefinition column) + public virtual string FormatPrimaryKey(TableDefinition table) + { + var columnDefinition = table.Columns.FirstOrDefault(x => x.IsPrimaryKey); + if (columnDefinition == null) + return string.Empty; + + string constraintName = string.IsNullOrEmpty(columnDefinition.PrimaryKeyName) + ? string.Format("PK_{0}", table.Name) + : columnDefinition.PrimaryKeyName; + + string columns = string.IsNullOrEmpty(columnDefinition.PrimaryKeyColumns) + ? GetQuotedColumnName(columnDefinition.Name) + : columnDefinition.PrimaryKeyColumns; + + string primaryKeyPart = string.Concat("PRIMARY KEY", columnDefinition.IsIndexed ? " CLUSTERED" : " NONCLUSTERED"); + + return string.Format(CreateConstraint, + GetQuotedTableName(table.Name), + GetQuotedName(constraintName), + primaryKeyPart, + columns); + } + + public virtual List Format(IEnumerable indexes) + { + return indexes.Select(Format).ToList(); + } + + public virtual string Format(IndexDefinition index) + { + string name = string.IsNullOrEmpty(index.Name) + ? string.Format("IX_{0}_{1}", index.TableName, index.ColumnName) + : index.Name; + + string columns = index.Columns.Any() + ? string.Join(",", index.Columns.Select(x => GetQuotedColumnName(x.Name))) + : GetQuotedColumnName(index.ColumnName); + + return string.Format(CreateIndex, GetIndexType(index.IndexType), " ", GetQuotedName(name), + GetQuotedTableName(index.TableName), columns); + } + + public virtual List Format(IEnumerable foreignKeys) + { + return foreignKeys.Select(Format).ToList(); + } + + public virtual string Format(ForeignKeyDefinition foreignKey) + { + string constraintName = string.IsNullOrEmpty(foreignKey.Name) + ? string.Format("FK_{0}_{1}_{2}", foreignKey.ForeignTable, foreignKey.PrimaryTable, foreignKey.PrimaryColumns.First()) + : foreignKey.Name; + + return string.Format(CreateForeignKeyConstraint, + GetQuotedTableName(foreignKey.ForeignTable), + GetQuotedName(constraintName), + GetQuotedColumnName(foreignKey.ForeignColumns.First()), + GetQuotedTableName(foreignKey.PrimaryTable), + GetQuotedColumnName(foreignKey.PrimaryColumns.First()), + "", ""); + } + + public virtual string Format(IEnumerable columns) + { + var sb = new StringBuilder(); + foreach (var column in columns) + { + sb.Append(Format(column) +",\n"); + } + return sb.ToString().TrimEnd(",\n"); + } + + public virtual string Format(ColumnDefinition column) { var clauses = new List(); @@ -349,19 +249,39 @@ namespace Umbraco.Core.Persistence.SqlSyntax return string.Join(" ", clauses.ToArray()); } - public virtual string FormatString(DatabaseModelDefinitions.ColumnDefinition column) + public virtual string FormatString(ColumnDefinition column) { return GetQuotedColumnName(column.Name); } - protected virtual string FormatType(DatabaseModelDefinitions.ColumnDefinition column) + protected virtual string FormatType(ColumnDefinition column) { - if (!column.Type.HasValue) + if (column.Type.HasValue == false && string.IsNullOrEmpty(column.CustomType) == false) return column.CustomType; - var dbType = DbTypeMap.ColumnDbTypeMap.First(x => x.Value == column.Type.Value).Key; - var definition = DbTypeMap.ColumnTypeMap.First(x => x.Key == dbType).Value; + if (column.HasSpecialDbType) + { + if (column.Size != default(int)) + { + return string.Format("{0}({1})", + GetSpecialDbType(column.DbType), + column.Size); + } + return GetSpecialDbType(column.DbType); + } + + Type type = column.Type.HasValue + ? DbTypeMap.ColumnDbTypeMap.First(x => x.Value == column.Type.Value).Key + : column.PropertyType; + + if (type == typeof (string)) + { + var valueOrDefault = column.Size != default(int) ? column.Size : DefaultStringLength; + return string.Format(StringLengthColumnDefinitionFormat, valueOrDefault); + } + + string definition = DbTypeMap.ColumnTypeMap.First(x => x.Key == type).Value; string dbTypeDefinition = column.Size != default(int) ? string.Format("{0}({1})", definition, column.Size) : definition; @@ -369,12 +289,23 @@ namespace Umbraco.Core.Persistence.SqlSyntax return dbTypeDefinition; } - protected virtual string FormatNullable(DatabaseModelDefinitions.ColumnDefinition column) + protected virtual string FormatNullable(ColumnDefinition column) { - return column.IsNullable ? string.Empty : "NOT NULL"; + return column.IsNullable ? "NULL" : "NOT NULL"; } - protected virtual string FormatDefaultValue(DatabaseModelDefinitions.ColumnDefinition column) + protected virtual string FormatConstraint(ColumnDefinition column) + { + if (string.IsNullOrEmpty(column.ConstraintName) && column.DefaultValue == null) + return string.Empty; + + return string.Format("CONSTRAINT {0}", + string.IsNullOrEmpty(column.ConstraintName) + ? GetQuotedName(string.Format("DF_{0}_{1}", column.TableName, column.Name)) + : column.ConstraintName); + } + + protected virtual string FormatDefaultValue(ColumnDefinition column) { if (column.DefaultValue == null) return string.Empty; @@ -386,20 +317,20 @@ namespace Umbraco.Core.Persistence.SqlSyntax if (string.IsNullOrEmpty(method)) return string.Empty; - return "DEFAULT " + method; + return string.Format(DefaultValueFormat, method); } - return "DEFAULT " + GetQuotedValue(column.DefaultValue.ToString()); + return string.Format(DefaultValueFormat, GetQuotedValue(column.DefaultValue.ToString())); } - protected virtual string FormatPrimaryKey(DatabaseModelDefinitions.ColumnDefinition column) + protected virtual string FormatPrimaryKey(ColumnDefinition column) { return string.Empty; } protected abstract string FormatSystemMethods(SystemMethods systemMethod); - protected abstract string FormatIdentity(DatabaseModelDefinitions.ColumnDefinition column); + protected abstract string FormatIdentity(ColumnDefinition column); public virtual string CreateTable { get { return "CREATE TABLE {0} ({1})"; } } public virtual string DropTable { get { return "DROP TABLE {0}"; } } diff --git a/src/Umbraco.Tests/Persistence/SqlCeTableByTableTest.cs b/src/Umbraco.Tests/Persistence/SqlCeTableByTableTest.cs index c1f0dd1d95..1cd04b024e 100644 --- a/src/Umbraco.Tests/Persistence/SqlCeTableByTableTest.cs +++ b/src/Umbraco.Tests/Persistence/SqlCeTableByTableTest.cs @@ -64,6 +64,8 @@ namespace Umbraco.Tests.Persistence { AppDomain.CurrentDomain.SetData("DataDirectory", null); + SyntaxConfig.SqlSyntaxProvider = null; + //reset the app context ApplicationContext.Current = null; Resolution.IsFrozen = false; diff --git a/src/Umbraco.Tests/Persistence/SqlTableByTableTest.cs b/src/Umbraco.Tests/Persistence/SqlTableByTableTest.cs index 0512b8bea7..82097c487e 100644 --- a/src/Umbraco.Tests/Persistence/SqlTableByTableTest.cs +++ b/src/Umbraco.Tests/Persistence/SqlTableByTableTest.cs @@ -51,6 +51,8 @@ namespace Umbraco.Tests.Persistence { AppDomain.CurrentDomain.SetData("DataDirectory", null); + SyntaxConfig.SqlSyntaxProvider = null; + //reset the app context ApplicationContext.Current = null; Resolution.IsFrozen = false; diff --git a/src/Umbraco.Tests/Persistence/SyntaxProvider/SqlSyntaxProviderTests.cs b/src/Umbraco.Tests/Persistence/SyntaxProvider/SqlSyntaxProviderTests.cs new file mode 100644 index 0000000000..6172c9d4f7 --- /dev/null +++ b/src/Umbraco.Tests/Persistence/SyntaxProvider/SqlSyntaxProviderTests.cs @@ -0,0 +1,46 @@ +using System; +using NUnit.Framework; +using Umbraco.Core.Models.Rdbms; +using Umbraco.Core.Persistence.DatabaseModelDefinitions; +using Umbraco.Core.Persistence.SqlSyntax; + +namespace Umbraco.Tests.Persistence.SyntaxProvider +{ + [TestFixture] + public class SqlSyntaxProviderTests + { + [SetUp] + public void SetUp() + { + SyntaxConfig.SqlSyntaxProvider = SqlCeSyntaxProvider.Instance; + } + + [Test] + public void Can_Generate_Create_Table_Statement() + { + var type = typeof (NodeDto); + var definition = DefinitionFactory.GetTableDefinition(type); + + string create = SyntaxConfig.SqlSyntaxProvider.Format(definition); + string primaryKey = SyntaxConfig.SqlSyntaxProvider.FormatPrimaryKey(definition); + var indexes = SyntaxConfig.SqlSyntaxProvider.Format(definition.Indexes); + var keys = SyntaxConfig.SqlSyntaxProvider.Format(definition.ForeignKeys); + + Console.WriteLine(create); + Console.WriteLine(primaryKey); + foreach (var sql in keys) + { + Console.WriteLine(sql); + } + + foreach (var sql in indexes) + { + Console.WriteLine(sql); + } + } + + [TearDown] + public void TearDown() + {} + } +} \ No newline at end of file diff --git a/src/Umbraco.Tests/Umbraco.Tests.csproj b/src/Umbraco.Tests/Umbraco.Tests.csproj index 307d442c68..3dbaefb4af 100644 --- a/src/Umbraco.Tests/Umbraco.Tests.csproj +++ b/src/Umbraco.Tests/Umbraco.Tests.csproj @@ -166,6 +166,7 @@ +