diff --git a/src/Umbraco.Core/Migrations/Install/DatabaseSchemaCreator.cs b/src/Umbraco.Core/Migrations/Install/DatabaseSchemaCreator.cs index b46cbb5b96..042c6117aa 100644 --- a/src/Umbraco.Core/Migrations/Install/DatabaseSchemaCreator.cs +++ b/src/Umbraco.Core/Migrations/Install/DatabaseSchemaCreator.cs @@ -116,8 +116,12 @@ namespace Umbraco.Core.Migrations.Install /// /// Initializes the database by creating the umbraco db schema. /// + /// This needs to execute as part of a transaction. public void InitializeDatabaseSchema() { + if (!_database.InTransaction) + throw new InvalidOperationException("Database is not in a transaction."); + var e = new DatabaseCreationEventArgs(); FireBeforeCreation(e); @@ -410,9 +414,14 @@ namespace Umbraco.Core.Migrations.Install /// If a table with the same name already exists, the parameter will determine /// whether the table is overwritten. If true, the table will be overwritten, whereas this method will /// not do anything if the parameter is false. + /// + /// This need to execute as part of a transaction. /// public void CreateTable(bool overwrite, Type modelType, DatabaseDataCreator dataCreation) { + if (!_database.InTransaction) + throw new InvalidOperationException("Database is not in a transaction."); + var tableDefinition = DefinitionFactory.GetTableDefinition(modelType, SqlSyntax); var tableName = tableDefinition.Name; @@ -430,65 +439,64 @@ namespace Umbraco.Core.Migrations.Install tableExist = false; } - if (tableExist == false) - { - //Execute the Create Table sql - var created = _database.Execute(new Sql(createSql)); - _logger.Info("Create Table '{TableName}' ({Created}): \n {Sql}", tableName, created, createSql); - - //If any statements exists for the primary key execute them here - if (string.IsNullOrEmpty(createPrimaryKeySql) == false) - { - var createdPk = _database.Execute(new Sql(createPrimaryKeySql)); - _logger.Info("Create Primary Key ({CreatedPk}):\n {Sql}", createdPk, createPrimaryKeySql); - } - - //Turn on identity insert if db provider is not mysql - if (SqlSyntax.SupportsIdentityInsert() && tableDefinition.Columns.Any(x => x.IsIdentity)) - _database.Execute(new Sql($"SET IDENTITY_INSERT {SqlSyntax.GetQuotedTableName(tableName)} ON ")); - - //Call the NewTable-event to trigger the insert of base/default data - //OnNewTable(tableName, _db, e, _logger); - - dataCreation.InitializeBaseData(tableName); - - //Turn off identity insert if db provider is not mysql - if (SqlSyntax.SupportsIdentityInsert() && tableDefinition.Columns.Any(x => x.IsIdentity)) - _database.Execute(new Sql($"SET IDENTITY_INSERT {SqlSyntax.GetQuotedTableName(tableName)} OFF;")); - - //Special case for MySql - if (SqlSyntax is MySqlSyntaxProvider && tableName.Equals("umbracoUser")) - { - _database.Update("SET id = @IdAfter WHERE id = @IdBefore AND userLogin = @Login", new { IdAfter = 0, IdBefore = 1, Login = "admin" }); - } - - //Loop through index statements and execute sql - foreach (var sql in indexSql) - { - var createdIndex = _database.Execute(new Sql(sql)); - _logger.Info("Create Index ({CreatedIndex}):\n {Sql}", createdIndex, sql); - } - - //Loop through foreignkey statements and execute sql - foreach (var sql in foreignSql) - { - var createdFk = _database.Execute(new Sql(sql)); - _logger.Info("Create Foreign Key ({CreatedFk}):\n {Sql}", createdFk, sql); - } - - if (overwrite) - { - _logger.Info("Table '{TableName}' was recreated", tableName); - } - else - { - _logger.Info("New table '{TableName}' was created", tableName); - } - } - else + if (tableExist) { // The table exists and was not recreated/overwritten. _logger.Info("Table '{TableName}' already exists - no changes were made", tableName); + return; + } + + //Execute the Create Table sql + var created = _database.Execute(new Sql(createSql)); + _logger.Info("Create Table '{TableName}' ({Created}): \n {Sql}", tableName, created, createSql); + + //If any statements exists for the primary key execute them here + if (string.IsNullOrEmpty(createPrimaryKeySql) == false) + { + var createdPk = _database.Execute(new Sql(createPrimaryKeySql)); + _logger.Info("Create Primary Key ({CreatedPk}):\n {Sql}", createdPk, createPrimaryKeySql); + } + + //Turn on identity insert if db provider is not mysql + if (SqlSyntax.SupportsIdentityInsert() && tableDefinition.Columns.Any(x => x.IsIdentity)) + _database.Execute(new Sql($"SET IDENTITY_INSERT {SqlSyntax.GetQuotedTableName(tableName)} ON ")); + + //Call the NewTable-event to trigger the insert of base/default data + //OnNewTable(tableName, _db, e, _logger); + + dataCreation.InitializeBaseData(tableName); + + //Turn off identity insert if db provider is not mysql + if (SqlSyntax.SupportsIdentityInsert() && tableDefinition.Columns.Any(x => x.IsIdentity)) + _database.Execute(new Sql($"SET IDENTITY_INSERT {SqlSyntax.GetQuotedTableName(tableName)} OFF;")); + + //Special case for MySql + if (SqlSyntax is MySqlSyntaxProvider && tableName.Equals("umbracoUser")) + { + _database.Update("SET id = @IdAfter WHERE id = @IdBefore AND userLogin = @Login", new { IdAfter = 0, IdBefore = 1, Login = "admin" }); + } + + //Loop through index statements and execute sql + foreach (var sql in indexSql) + { + var createdIndex = _database.Execute(new Sql(sql)); + _logger.Info("Create Index ({CreatedIndex}):\n {Sql}", createdIndex, sql); + } + + //Loop through foreignkey statements and execute sql + foreach (var sql in foreignSql) + { + var createdFk = _database.Execute(new Sql(sql)); + _logger.Info("Create Foreign Key ({CreatedFk}):\n {Sql}", createdFk, sql); + } + + if (overwrite) + { + _logger.Info("Table '{TableName}' was recreated", tableName); + } + else + { + _logger.Info("New table '{TableName}' was created", tableName); } } diff --git a/src/Umbraco.Tests/Persistence/DatabaseContextTests.cs b/src/Umbraco.Tests/Persistence/DatabaseContextTests.cs index d45016ba11..32689fe192 100644 --- a/src/Umbraco.Tests/Persistence/DatabaseContextTests.cs +++ b/src/Umbraco.Tests/Persistence/DatabaseContextTests.cs @@ -14,6 +14,7 @@ using Umbraco.Core.Persistence.Mappers; using Umbraco.Core.Persistence.SqlSyntax; using Umbraco.Core.Services; using Umbraco.Tests.TestHelpers; +using Umbraco.Web.Security; namespace Umbraco.Tests.Persistence { @@ -88,9 +89,11 @@ namespace Umbraco.Tests.Persistence // create the umbraco database DatabaseSchemaCreator schemaHelper; using (var database = _databaseFactory.CreateDatabase()) + using (var transaction = database.GetTransaction()) { schemaHelper = new DatabaseSchemaCreator(database, _logger); schemaHelper.InitializeDatabaseSchema(); + transaction.Complete(); } var umbracoNodeTable = schemaHelper.TableExists("umbracoNode");