Fixed dropping of database tables during site reset.

This fixes an issue where only a subset of the actual tables were being deleted due to a minimal shell context.
This commit is contained in:
Sipke Schoorstra
2015-08-03 17:20:55 +01:00
parent 09f3e2ad2f
commit 3cd39bcc73
7 changed files with 73 additions and 45 deletions

View File

@@ -11,6 +11,5 @@ namespace Orchard.ImportExport.Models {
public string DatabaseTablePrefix { get; set; }
public IEnumerable<string> EnabledFeatures { get; set; }
public XDocument RecipeDocument { get; set; }
public bool DropExistingTables { get; set; }
}
}

View File

@@ -87,6 +87,8 @@
<Compile Include="Providers\ExportActions\BuildRecipeAction.cs" />
<Compile Include="Models\ExportActionConfigurationContext.cs" />
<Compile Include="Models\ImportActionConfigurationContext.cs" />
<Compile Include="Services\DatabaseManager.cs" />
<Compile Include="Services\IDatabaseManager.cs" />
<Compile Include="ViewModels\RecipeExecutionStepViewModel.cs" />
<Compile Include="Services\ISetupService.cs" />
<Compile Include="Models\SetupContext.cs" />

View File

@@ -23,6 +23,7 @@ namespace Orchard.ImportExport.Providers.ImportActions {
private readonly IEnumerable<IRecipeExecutionStep> _recipeExecutionSteps;
private readonly IRecipeParser _recipeParser;
private readonly IRecipeExecutor _recipeExecutor;
private readonly IDatabaseManager _databaseManager;
public ExecuteRecipeAction(
IOrchardServices orchardServices,
@@ -31,7 +32,8 @@ namespace Orchard.ImportExport.Providers.ImportActions {
IFeatureManager featureManager,
IEnumerable<IRecipeExecutionStep> recipeExecutionSteps,
IRecipeParser recipeParser,
IRecipeExecutor recipeExecutor) {
IRecipeExecutor recipeExecutor,
IDatabaseManager databaseManager) {
_orchardServices = orchardServices;
_setupService = setupService;
@@ -40,6 +42,7 @@ namespace Orchard.ImportExport.Providers.ImportActions {
_recipeExecutionSteps = recipeExecutionSteps;
_recipeParser = recipeParser;
_recipeExecutor = recipeExecutor;
_databaseManager = databaseManager;
}
public override string Name { get { return "ExecuteRecipe"; } }
@@ -153,8 +156,11 @@ namespace Orchard.ImportExport.Providers.ImportActions {
}
private string Setup(XDocument recipeDocument) {
// Delete the tenant tables.
DropTenantDatabaseTables();
// Setup.
var setupContext = new SetupContext {
DropExistingTables = true,
RecipeDocument = recipeDocument,
AdminPassword = SuperUserPassword,
AdminUsername = _orchardServices.WorkContext.CurrentSite.SuperUser,
@@ -164,6 +170,7 @@ namespace Orchard.ImportExport.Providers.ImportActions {
SiteName = _orchardServices.WorkContext.CurrentSite.SiteName,
EnabledFeatures = _featureManager.GetEnabledFeatures().Select(x => x.Id).ToArray()
};
return _setupService.Setup(setupContext);
}
@@ -184,5 +191,10 @@ namespace Orchard.ImportExport.Providers.ImportActions {
step.Step.UpdateStep(context);
}
}
private void DropTenantDatabaseTables() {
_databaseManager.DropTenantDatabaseTables();
_orchardServices.TransactionManager.RequireNew();
}
}
}

View File

@@ -0,0 +1,42 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Orchard.Data;
using Orchard.Data.Migration.Interpreters;
using Orchard.Data.Migration.Schema;
using Orchard.Logging;
namespace Orchard.ImportExport.Services {
public class DatabaseManager : Component, IDatabaseManager {
private readonly ISessionFactoryHolder _sessionFactoryHolder;
private readonly IDataMigrationInterpreter _dataMigrationInterpreter;
public DatabaseManager(
ISessionFactoryHolder sessionFactoryHolder,
IDataMigrationInterpreter dataMigrationInterpreter) {
_sessionFactoryHolder = sessionFactoryHolder;
_dataMigrationInterpreter = dataMigrationInterpreter;
}
public IEnumerable<string> GetTenantDatabaseTableNames() {
var configuration = _sessionFactoryHolder.GetConfiguration();
var result = configuration.ClassMappings.Select(x => x.Table.Name);
return result.ToArray();
}
public void DropTenantDatabaseTables() {
var tableNames = GetTenantDatabaseTableNames();
var schemaBuilder = new SchemaBuilder(_dataMigrationInterpreter);
foreach (var tableName in tableNames) {
try {
schemaBuilder.DropTable(schemaBuilder.RemoveDataTablePrefix(tableName));
}
catch (Exception ex) {
Logger.Warning(ex, "Failed to drop table '{0}'.", tableName);
}
}
}
}
}

View File

@@ -0,0 +1,8 @@
using System.Collections.Generic;
namespace Orchard.ImportExport.Services {
public interface IDatabaseManager {
IEnumerable<string> GetTenantDatabaseTableNames();
void DropTenantDatabaseTables();
}
}

View File

@@ -87,29 +87,11 @@ namespace Orchard.ImportExport.Services
// Initialize database explicitly, and store shell descriptor.
using (var bootstrapLifetimeScope = _shellContainerFactory.CreateContainer(shellSettings, shellBlueprint)) {
using (var environment = bootstrapLifetimeScope.CreateWorkContextScope()) {
// Check if the database is already created (in case an exception occured in the second phase).
var schemaBuilder = new SchemaBuilder(environment.Resolve<IDataMigrationInterpreter>());
var installationPresent = true;
try {
var tablePrefix = String.IsNullOrEmpty(shellSettings.DataTablePrefix) ? "" : shellSettings.DataTablePrefix + "_";
schemaBuilder.ExecuteSql("SELECT * FROM " + tablePrefix + "Settings_ShellDescriptorRecord");
}
catch {
installationPresent = false;
}
if (installationPresent) {
if (context.DropExistingTables) {
DropTenantDatabaseTables(environment);
}
}
// Make a workaround to avoid the Transaction issue for PostgreSQL.
// Workaround to avoid a Transaction issue with PostgreSQL.
environment.Resolve<ITransactionManager>().RequireNew();
var schemaBuilder = new SchemaBuilder(environment.Resolve<IDataMigrationInterpreter>());
schemaBuilder.CreateTable("Orchard_Framework_DataMigrationRecord", table => table
.Column<int>("Id", column => column.PrimaryKey().Identity())
.Column<string>("DataMigrationClass")
@@ -131,10 +113,7 @@ namespace Orchard.ImportExport.Services
while ( _processingEngine.AreTasksPending() )
_processingEngine.ExecuteNextTask();
// Creating a standalone environment.
// In theory this environment can be used to resolve any normal components by interface, and those
// components will exist entirely in isolation - no crossover between the safemode container currently in effect.
// Create a standalone environment.
// Must mark state as Running - otherwise standalone environment is created "for setup".
shellSettings.State = TenantState.Running;
using (var environment = _orchardHost.CreateStandaloneEnvironment(shellSettings)) {
@@ -193,19 +172,5 @@ namespace Orchard.ImportExport.Services
return executionId;
}
private void DropTenantDatabaseTables(IWorkContextScope environment) {
var sessionFactoryHolder = environment.Resolve<ISessionFactoryHolder>();
var schemaBuilder = new SchemaBuilder(environment.Resolve<IDataMigrationInterpreter>());
var configuration = sessionFactoryHolder.GetConfiguration();
foreach (var mapping in configuration.ClassMappings) {
try {
schemaBuilder.DropTable(mapping.Table.Name);
}
catch (Exception ex) {
Logger.Warning(ex, "Failed to drop table '{0}'.", mapping.Table.Name);
}
}
}
}
}

View File

@@ -13,19 +13,19 @@ namespace Orchard.Recipes.Providers.Executors {
private readonly IRecipeHarvester _recipeHarvester;
private readonly IRecipeStepQueue _recipeStepQueue;
private readonly IRepository<RecipeStepResultRecord> _recipeStepResultRecordRepository;
private readonly ISessionLocator _sessionLocator;
private readonly ITransactionManager _transactionManager;
public RecipesStep(
IRecipeHarvester recipeHarvester,
IRecipeStepQueue recipeStepQueue,
IRepository<RecipeStepResultRecord> recipeStepResultRecordRepository,
ISessionLocator sessionLocator,
ITransactionManager transactionManager,
RecipeExecutionLogger logger) : base(logger) {
_recipeHarvester = recipeHarvester;
_recipeStepQueue = recipeStepQueue;
_recipeStepResultRecordRepository = recipeStepResultRecordRepository;
_sessionLocator = sessionLocator;
_transactionManager = transactionManager;
}
public override string Name { get { return "Recipes"; } }
@@ -38,7 +38,7 @@ namespace Orchard.Recipes.Providers.Executors {
public override void Execute(RecipeExecutionContext context) {
var recipeElements = context.RecipeStep.Step.Elements();
var recipesDictionary = new Dictionary<string, IDictionary<string, Recipe>>();
var session = _sessionLocator.For(typeof(RecipeStepResultRecord));
var session = _transactionManager.GetSession();
foreach (var recipeElement in recipeElements) {
var extensionId = recipeElement.Attr("ExtensionId");