From 213451e442be4ffe975368c25234c4e213543cff Mon Sep 17 00:00:00 2001 From: Morten Christensen Date: Fri, 30 Nov 2012 18:48:20 -0100 Subject: [PATCH] Implementing the MigrationRunner, which will be used for database upgrades. Refactoring a few bits in the syntax of the migration models. Adding an extension of the PluginManager to find migrations by Type and Attribute. --- src/Umbraco.Core/DatabaseContext.cs | 17 ++++- .../Persistence/Migrations/MigrationRunner.cs | 71 +++++++++++++++++++ .../Migrations/Model/ColumnDefinition.cs | 8 +-- .../Migrations/Model/ModificationType.cs | 13 ++++ .../Migrations/PluginManagerExtension.cs | 13 ++++ .../Expressions/AlterColumnExpression.cs | 2 +- .../Alter/Table/AlterTableSyntaxBuilder.cs | 6 +- .../Expressions/CreateColumnExpression.cs | 2 +- .../SqlSyntax/SqlSyntaxProviderBase.cs | 2 +- src/Umbraco.Core/Umbraco.Core.csproj | 3 + .../install/utills/p.aspx.cs | 2 +- 11 files changed, 123 insertions(+), 16 deletions(-) create mode 100644 src/Umbraco.Core/Persistence/Migrations/MigrationRunner.cs create mode 100644 src/Umbraco.Core/Persistence/Migrations/Model/ModificationType.cs create mode 100644 src/Umbraco.Core/Persistence/Migrations/PluginManagerExtension.cs diff --git a/src/Umbraco.Core/DatabaseContext.cs b/src/Umbraco.Core/DatabaseContext.cs index 44a943e198..655801dddf 100644 --- a/src/Umbraco.Core/DatabaseContext.cs +++ b/src/Umbraco.Core/DatabaseContext.cs @@ -9,6 +9,7 @@ using System.Xml.Linq; using Umbraco.Core.Configuration; using Umbraco.Core.Logging; using Umbraco.Core.Persistence; +using Umbraco.Core.Persistence.Migrations; using Umbraco.Core.Persistence.SqlSyntax; namespace Umbraco.Core @@ -296,7 +297,7 @@ namespace Umbraco.Core _configured = true; } - internal Result CreateDatabaseSchemaAndData() + internal Result CreateDatabaseSchemaAndDataOrUpgrade() { if (_configured == false || (string.IsNullOrEmpty(_connectionString) || string.IsNullOrEmpty(ProviderName))) { @@ -306,7 +307,19 @@ namespace Umbraco.Core try { var database = new Database(_connectionString, ProviderName); - database.CreateDatabaseSchema(); + //If Configuration Status is empty its a new install - otherwise upgrade the existing + if (string.IsNullOrEmpty(GlobalSettings.ConfigurationStatus)) + { + database.CreateDatabaseSchema(); + } + else + { + var configuredVersion = new Version(GlobalSettings.ConfigurationStatus); + var targetVersion = UmbracoVersion.Current; + var runner = new MigrationRunner(configuredVersion, targetVersion); + var upgraded = runner.Execute(database, true); + } + return new Result { Message = "Installation completed!", Success = true, Percentage = "100" }; } catch (Exception ex) diff --git a/src/Umbraco.Core/Persistence/Migrations/MigrationRunner.cs b/src/Umbraco.Core/Persistence/Migrations/MigrationRunner.cs new file mode 100644 index 0000000000..c0c0cd08a2 --- /dev/null +++ b/src/Umbraco.Core/Persistence/Migrations/MigrationRunner.cs @@ -0,0 +1,71 @@ +using System; +using System.Linq; +using Umbraco.Core.Logging; + +namespace Umbraco.Core.Persistence.Migrations +{ + /// + /// Represents the Migration Runner, which is used to apply migrations to + /// the umbraco database. + /// + public class MigrationRunner + { + private readonly Version _configuredVersion; + private readonly Version _targetVersion; + + public MigrationRunner(Version configuredVersion, Version targetVersion) + { + _configuredVersion = configuredVersion; + _targetVersion = targetVersion; + } + + /// + /// Executes the migrations against the database. + /// + /// The PetaPoco Database, which the migrations will be run against + /// Boolean indicating whether this is an upgrade or downgrade + /// True if migrations were applied, otherwise False + public bool Execute(Database database, bool isUpgrade) + { + LogHelper.Info("Initializing database migration"); + + var foundMigrations = PluginManager.Current.FindMigrations(); + var migrations = (from migration in foundMigrations + let migrationAttribute = migration.GetType().FirstAttribute() + where migrationAttribute != null + where + migrationAttribute.TargetVersion > _configuredVersion && + migrationAttribute.TargetVersion <= _targetVersion + select migration); + + //Loop through migrations to generate sql + var context = new MigrationContext(); + foreach (MigrationBase migration in migrations) + { + if (isUpgrade) + { + migration.GetUpExpressions(context); + } + else + { + migration.GetDownExpressions(context); + } + } + + //Transactional execution of the sql that was generated from the found migrationsS + using (Transaction transaction = database.GetTransaction()) + { + foreach (var expression in context.Expressions) + { + var sql = expression.ToString(); + LogHelper.Info("Executing sql: " + sql); + database.Execute(sql); + } + + transaction.Complete(); + } + + return true; + } + } +} \ No newline at end of file diff --git a/src/Umbraco.Core/Persistence/Migrations/Model/ColumnDefinition.cs b/src/Umbraco.Core/Persistence/Migrations/Model/ColumnDefinition.cs index c41aebf0ab..1813225ffe 100644 --- a/src/Umbraco.Core/Persistence/Migrations/Model/ColumnDefinition.cs +++ b/src/Umbraco.Core/Persistence/Migrations/Model/ColumnDefinition.cs @@ -18,12 +18,6 @@ namespace Umbraco.Core.Persistence.Migrations.Model public virtual bool IsNullable { get; set; } public virtual bool IsUnique { get; set; } public virtual string TableName { get; set; } - public virtual ColumnModificationType ModificationType { get; set; } - } - - public enum ColumnModificationType - { - Create, - Alter + public virtual ModificationType ModificationType { get; set; } } } \ No newline at end of file diff --git a/src/Umbraco.Core/Persistence/Migrations/Model/ModificationType.cs b/src/Umbraco.Core/Persistence/Migrations/Model/ModificationType.cs new file mode 100644 index 0000000000..b9858a4315 --- /dev/null +++ b/src/Umbraco.Core/Persistence/Migrations/Model/ModificationType.cs @@ -0,0 +1,13 @@ +namespace Umbraco.Core.Persistence.Migrations.Model +{ + public enum ModificationType + { + Create, + Alter, + Drop, + Rename, + Insert, + Update, + Delete + } +} \ No newline at end of file diff --git a/src/Umbraco.Core/Persistence/Migrations/PluginManagerExtension.cs b/src/Umbraco.Core/Persistence/Migrations/PluginManagerExtension.cs new file mode 100644 index 0000000000..8540f8dbf7 --- /dev/null +++ b/src/Umbraco.Core/Persistence/Migrations/PluginManagerExtension.cs @@ -0,0 +1,13 @@ +using System.Collections.Generic; + +namespace Umbraco.Core.Persistence.Migrations +{ + internal static class PluginManagerExtension + { + public static IEnumerable FindMigrations(this PluginManager resolver) + { + var types = resolver.ResolveTypesWithAttribute(); + return resolver.CreateInstances(types); + } + } +} \ No newline at end of file diff --git a/src/Umbraco.Core/Persistence/Migrations/Syntax/Alter/Expressions/AlterColumnExpression.cs b/src/Umbraco.Core/Persistence/Migrations/Syntax/Alter/Expressions/AlterColumnExpression.cs index 32eaf9da71..b8dce3200e 100644 --- a/src/Umbraco.Core/Persistence/Migrations/Syntax/Alter/Expressions/AlterColumnExpression.cs +++ b/src/Umbraco.Core/Persistence/Migrations/Syntax/Alter/Expressions/AlterColumnExpression.cs @@ -6,7 +6,7 @@ namespace Umbraco.Core.Persistence.Migrations.Syntax.Alter.Expressions { public AlterColumnExpression() { - Column = new ColumnDefinition() { ModificationType = ColumnModificationType.Alter }; + Column = new ColumnDefinition() { ModificationType = ModificationType.Alter }; } public virtual string SchemaName { get; set; } diff --git a/src/Umbraco.Core/Persistence/Migrations/Syntax/Alter/Table/AlterTableSyntaxBuilder.cs b/src/Umbraco.Core/Persistence/Migrations/Syntax/Alter/Table/AlterTableSyntaxBuilder.cs index 79d5ba3630..b4f2ede72e 100644 --- a/src/Umbraco.Core/Persistence/Migrations/Syntax/Alter/Table/AlterTableSyntaxBuilder.cs +++ b/src/Umbraco.Core/Persistence/Migrations/Syntax/Alter/Table/AlterTableSyntaxBuilder.cs @@ -28,7 +28,7 @@ namespace Umbraco.Core.Persistence.Migrations.Syntax.Alter.Table public IAlterTableColumnOptionSyntax WithDefaultValue(object value) { - if (CurrentColumn.ModificationType == ColumnModificationType.Alter) + if (CurrentColumn.ModificationType == ModificationType.Alter) { var dc = new AlterDefaultConstraintExpression { @@ -213,7 +213,7 @@ namespace Umbraco.Core.Persistence.Migrations.Syntax.Alter.Table public IAlterTableColumnSyntax AddColumn(string name) { - var column = new ColumnDefinition { Name = name, ModificationType = ColumnModificationType.Create }; + var column = new ColumnDefinition { Name = name, ModificationType = ModificationType.Create }; var createColumn = new CreateColumnExpression { Column = column, @@ -229,7 +229,7 @@ namespace Umbraco.Core.Persistence.Migrations.Syntax.Alter.Table public IAlterTableColumnSyntax AlterColumn(string name) { - var column = new ColumnDefinition { Name = name, ModificationType = ColumnModificationType.Alter }; + var column = new ColumnDefinition { Name = name, ModificationType = ModificationType.Alter }; var alterColumn = new AlterColumnExpression { Column = column, diff --git a/src/Umbraco.Core/Persistence/Migrations/Syntax/Expressions/CreateColumnExpression.cs b/src/Umbraco.Core/Persistence/Migrations/Syntax/Expressions/CreateColumnExpression.cs index 592eac3e85..53279cd3ea 100644 --- a/src/Umbraco.Core/Persistence/Migrations/Syntax/Expressions/CreateColumnExpression.cs +++ b/src/Umbraco.Core/Persistence/Migrations/Syntax/Expressions/CreateColumnExpression.cs @@ -8,7 +8,7 @@ namespace Umbraco.Core.Persistence.Migrations.Syntax.Expressions { public CreateColumnExpression() { - Column = new ColumnDefinition { ModificationType = ColumnModificationType.Create }; + Column = new ColumnDefinition { ModificationType = ModificationType.Create }; } public virtual string SchemaName { get; set; } diff --git a/src/Umbraco.Core/Persistence/SqlSyntax/SqlSyntaxProviderBase.cs b/src/Umbraco.Core/Persistence/SqlSyntax/SqlSyntaxProviderBase.cs index 8f677be100..a4e18fc7a0 100644 --- a/src/Umbraco.Core/Persistence/SqlSyntax/SqlSyntaxProviderBase.cs +++ b/src/Umbraco.Core/Persistence/SqlSyntax/SqlSyntaxProviderBase.cs @@ -371,7 +371,7 @@ namespace Umbraco.Core.Persistence.SqlSyntax protected virtual string FormatNullable(Migrations.Model.ColumnDefinition column) { - return !column.IsNullable ? "NOT NULL" : string.Empty; + return column.IsNullable ? string.Empty : "NOT NULL"; } protected virtual string FormatDefaultValue(Migrations.Model.ColumnDefinition column) diff --git a/src/Umbraco.Core/Umbraco.Core.csproj b/src/Umbraco.Core/Umbraco.Core.csproj index e952407112..3c2461d637 100644 --- a/src/Umbraco.Core/Umbraco.Core.csproj +++ b/src/Umbraco.Core/Umbraco.Core.csproj @@ -196,12 +196,15 @@ + + + diff --git a/src/Umbraco.Web/umbraco.presentation/install/utills/p.aspx.cs b/src/Umbraco.Web/umbraco.presentation/install/utills/p.aspx.cs index 1bcbfd5bdd..4a0cf39b6d 100644 --- a/src/Umbraco.Web/umbraco.presentation/install/utills/p.aspx.cs +++ b/src/Umbraco.Web/umbraco.presentation/install/utills/p.aspx.cs @@ -58,7 +58,7 @@ namespace umbraco.presentation.install.utills { LogHelper.Info

("Running 'installOrUpgrade' service"); - var result = DatabaseContext.Current.CreateDatabaseSchemaAndData(); + var result = DatabaseContext.Current.CreateDatabaseSchemaAndDataOrUpgrade(); var js = new JavaScriptSerializer(); var jsonResult = js.Serialize(result);