diff --git a/src/Orchard.Tests/DataUtility.cs b/src/Orchard.Tests/DataUtility.cs index 40e2c0ead..fabace2ff 100644 --- a/src/Orchard.Tests/DataUtility.cs +++ b/src/Orchard.Tests/DataUtility.cs @@ -9,6 +9,7 @@ using FluentNHibernate.Cfg.Db; using NHibernate; using NHibernate.Tool.hbm2ddl; using Orchard.Data; +using Orchard.Data.Migrations; using Orchard.Environment; namespace Orchard.Tests { @@ -18,7 +19,7 @@ namespace Orchard.Tests { //var persistenceModel = AutoMap.Source(new Types(types)) // .Alterations(alt => AddAlterations(alt, types)) // .Conventions.AddFromAssemblyOf(); - var persistenceModel = HackSessionLocator.CreatePersistenceModel(types.Select(t => new RecordDescriptor { Prefix = "Test", Type = t })); + var persistenceModel = DatabaseCoordinatorBase.CreatePersistenceModel(types.Select(t => new RecordDescriptor { Prefix = "Test", Type = t })); return Fluently.Configure() .Database(SQLiteConfiguration.Standard.UsingFile(fileName).ShowSql()) diff --git a/src/Orchard.Web/Modules/Orchard.Setup/Controllers/SetupController.cs b/src/Orchard.Web/Modules/Orchard.Setup/Controllers/SetupController.cs index 372434d19..38c6a08dc 100644 --- a/src/Orchard.Web/Modules/Orchard.Setup/Controllers/SetupController.cs +++ b/src/Orchard.Web/Modules/Orchard.Setup/Controllers/SetupController.cs @@ -64,18 +64,16 @@ namespace Orchard.Setup.Controllers { DataProvider = model.DatabaseOptions ? "SQLite" : "SqlServer", DataConnectionString = model.DatabaseConnectionString }; - - // initialize the database: - // provider: SqlServer or SQLite - // dataFolder: physical path (map before calling). Builtin database will be created in this location - // connectionString: optional - if provided the dataFolder is essentially ignored, but should still be passed in - _databaseMigrationManager.CreateCoordinator(shellSettings.DataProvider, Server.MapPath("~/App_Data"), shellSettings.DataConnectionString); - + // 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 using (var finiteEnvironment = _orchardHost.CreateStandaloneEnvironment(shellSettings)) { try { + // initialize database before the transaction is created + var sessionFactoryHolder = finiteEnvironment.Resolve(); + sessionFactoryHolder.UpdateSchema(); + var contentManager = finiteEnvironment.Resolve(); // create superuser diff --git a/src/Orchard/Data/DataModule.cs b/src/Orchard/Data/DataModule.cs index 3c41bf223..5d1bea6fe 100644 --- a/src/Orchard/Data/DataModule.cs +++ b/src/Orchard/Data/DataModule.cs @@ -4,7 +4,6 @@ namespace Orchard.Data { public class DataModule : Module { protected override void Load(ContainerBuilder builder) { builder.RegisterGeneric(typeof (Repository<>)).As(typeof (IRepository<>)).FactoryScoped(); - builder.Register().As().ContainerScoped(); } } } \ No newline at end of file diff --git a/src/Orchard/Data/HackSessionLocator.cs b/src/Orchard/Data/HackSessionLocator.cs deleted file mode 100644 index 3a7f8f4f6..000000000 --- a/src/Orchard/Data/HackSessionLocator.cs +++ /dev/null @@ -1,97 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading; -using System.Web.Hosting; -using FluentNHibernate.Automapping; -using FluentNHibernate.Automapping.Alterations; -using FluentNHibernate.Cfg; -using FluentNHibernate.Cfg.Db; -using FluentNHibernate.Conventions.Helpers; -using NHibernate; -using NHibernate.Tool.hbm2ddl; -using Orchard.Data.Conventions; -using Orchard.Environment; -using Orchard.ContentManagement.Records; - -namespace Orchard.Data { - public class HackSessionLocator : ISessionLocator, IDisposable { - private readonly ICompositionStrategy _compositionStrategy; - private readonly ITransactionManager _transactionManager; - private static ISessionFactory _sessionFactory; - private ISession _session; - - public HackSessionLocator(ICompositionStrategy compositionStrategy, ITransactionManager transactionManager) { - _compositionStrategy = compositionStrategy; - _transactionManager = transactionManager; - } - - private ISessionFactory BindSessionFactory() { - // TEMP: a real scenario would call for a session factory locator - // that would eventually imply the need for configuration against one or more actual sources - // and a means to enlist record types from active modules into correct session factory - - var hackPath = HostingEnvironment.MapPath("~/App_Data/hack.db"); - - var database = SQLiteConfiguration.Standard.UsingFile(hackPath); - - var recordDescriptors = _compositionStrategy.GetRecordDescriptors(); - - return _sessionFactory ?? - Interlocked.CompareExchange( - ref _sessionFactory, - BuildSessionFactory(database, recordDescriptors), null) ?? _sessionFactory; - - } - - private static ISessionFactory BuildSessionFactory(IPersistenceConfigurer database, IEnumerable recordDescriptors) { - return Fluently.Configure() - .Database(database) - .Mappings(m => m.AutoMappings.Add(CreatePersistenceModel(recordDescriptors))) - .ExposeConfiguration(c => new SchemaUpdate(c).Execute(false /*script*/, true /*doUpdate*/)) - .BuildSessionFactory(); - } - - public static AutoPersistenceModel CreatePersistenceModel(IEnumerable recordDescriptors) { - var types = recordDescriptors.Select(d => d.Type); - return AutoMap.Source(new TypeSource(types)) - // Ensure that namespaces of types are never auto-imported, so that - // identical type names from different namespaces can be mapped without ambiguity - .Conventions.Setup(x => x.Add(AutoImport.Never())) - .Conventions.Add(new RecordTableNameConvention(recordDescriptors)) - .Alterations(alt => { - foreach (var recordAssembly in recordDescriptors.Select(x => x.Type.Assembly).Distinct()) { - alt.Add(new AutoMappingOverrideAlteration(recordAssembly)); - } - alt.AddFromAssemblyOf(); - alt.Add(new ContentItemAlteration(recordDescriptors)); - }) - .Conventions.AddFromAssemblyOf(); - } - - private class TypeSource : ITypeSource { - private readonly IEnumerable _recordTypes; - - public TypeSource(IEnumerable recordTypes) { - _recordTypes = recordTypes; - } - - public IEnumerable GetTypes() { - return _recordTypes; - } - } - - public ISession For(Type entityType) { - var sessionFactory = BindSessionFactory(); - _transactionManager.Demand(); - return _session ?? Interlocked.CompareExchange(ref _session, sessionFactory.OpenSession(), null) ?? _session; - } - - public void Dispose() { - //if (_session != null) { - // //_session.Flush(); - // _session.Close(); - //} - } - } -} \ No newline at end of file diff --git a/src/Orchard/Data/ISessionLocator.cs b/src/Orchard/Data/ISessionLocator.cs index b8583f98a..372c60d24 100644 --- a/src/Orchard/Data/ISessionLocator.cs +++ b/src/Orchard/Data/ISessionLocator.cs @@ -2,7 +2,7 @@ using System; using NHibernate; namespace Orchard.Data { - public interface ISessionLocator { + public interface ISessionLocator : IDependency { ISession For(Type entityType); } } \ No newline at end of file diff --git a/src/Orchard/Data/Migrations/DatabaseCoordinatorBase.cs b/src/Orchard/Data/Migrations/DatabaseCoordinatorBase.cs index 0d1d3bf66..426545c9c 100644 --- a/src/Orchard/Data/Migrations/DatabaseCoordinatorBase.cs +++ b/src/Orchard/Data/Migrations/DatabaseCoordinatorBase.cs @@ -61,7 +61,7 @@ namespace Orchard.Data.Migrations { .BuildSessionFactory(); } - static AutoPersistenceModel CreatePersistenceModel(IEnumerable recordDescriptors) { + public static AutoPersistenceModel CreatePersistenceModel(IEnumerable recordDescriptors) { return AutoMap.Source(new TypeSource(recordDescriptors)) // Ensure that namespaces of types are never auto-imported, so that // identical type names from different namespaces can be mapped without ambiguity diff --git a/src/Orchard/Data/Migrations/IDatabaseMigrationManager.cs b/src/Orchard/Data/Migrations/IDatabaseMigrationManager.cs index 921d7e1fb..964f24360 100644 --- a/src/Orchard/Data/Migrations/IDatabaseMigrationManager.cs +++ b/src/Orchard/Data/Migrations/IDatabaseMigrationManager.cs @@ -1,5 +1,5 @@ namespace Orchard.Data.Migrations { - public interface IDatabaseMigrationManager { + public interface IDatabaseMigrationManager : IDependency { IDatabaseCoordinator CreateCoordinator(string provider, string dataFolder, string connectionString); } } diff --git a/src/Orchard/Data/Migrations/SQLiteDatabaseCoordinator.cs b/src/Orchard/Data/Migrations/SQLiteDatabaseCoordinator.cs index 2c90f231c..955552c95 100644 --- a/src/Orchard/Data/Migrations/SQLiteDatabaseCoordinator.cs +++ b/src/Orchard/Data/Migrations/SQLiteDatabaseCoordinator.cs @@ -14,6 +14,10 @@ namespace Orchard.Data.Migrations { protected override IPersistenceConfigurer GetPersistenceConfigurer() { var persistence = SQLiteConfiguration.Standard; if (string.IsNullOrEmpty(_connectionString)) { + + if (!Directory.Exists(_dataFolder)) + Directory.CreateDirectory(_dataFolder); + persistence = persistence.UsingFile(Path.Combine(_dataFolder, "Orchard.db")); } else { diff --git a/src/Orchard/Data/SessionFactoryHolder.cs b/src/Orchard/Data/SessionFactoryHolder.cs new file mode 100644 index 000000000..15ade6961 --- /dev/null +++ b/src/Orchard/Data/SessionFactoryHolder.cs @@ -0,0 +1,59 @@ +using System.IO; +using System.Web.Hosting; +using NHibernate; +using Orchard.Data.Migrations; +using Orchard.Environment; +using Orchard.Environment.Configuration; + +namespace Orchard.Data { + public interface ISessionFactoryHolder : ISingletonDependency { + ISessionFactory GetSessionFactory(); + void UpdateSchema(); + } + + public class SessionFactoryHolder : ISessionFactoryHolder { + private readonly IShellSettings _shellSettings; + private readonly ICompositionStrategy _compositionStrategy; + private readonly IDatabaseMigrationManager _databaseMigrationManager; + + private ISessionFactory _sessionFactory; + + public SessionFactoryHolder( + IShellSettings shellSettings, + ICompositionStrategy compositionStrategy, + IDatabaseMigrationManager databaseMigrationManager) { + _shellSettings = shellSettings; + _compositionStrategy = compositionStrategy; + _databaseMigrationManager = databaseMigrationManager; + } + + + public void UpdateSchema() { + var coordinator = GetDatabaseCoordinator(); + coordinator.UpdateSchema(_compositionStrategy.GetRecordDescriptors()); + } + + public ISessionFactory GetSessionFactory() { + lock(this) { + if (_sessionFactory == null) { + _sessionFactory = BuildSessionFactory(); + } + } + return _sessionFactory; + } + + private ISessionFactory BuildSessionFactory() { + var coordinator = GetDatabaseCoordinator(); + return coordinator.BuildSessionFactory(_compositionStrategy.GetRecordDescriptors()); + } + + + private IDatabaseCoordinator GetDatabaseCoordinator() { + var sitesPath = HostingEnvironment.MapPath("~/App_Data/Sites"); + var shellPath = Path.Combine(sitesPath, _shellSettings.Name); + return _databaseMigrationManager.CreateCoordinator(_shellSettings.DataProvider, shellPath, _shellSettings.DataConnectionString); + } + } + + +} diff --git a/src/Orchard/Data/SessionLocator.cs b/src/Orchard/Data/SessionLocator.cs new file mode 100644 index 000000000..c74667152 --- /dev/null +++ b/src/Orchard/Data/SessionLocator.cs @@ -0,0 +1,28 @@ +using System; +using NHibernate; + +namespace Orchard.Data { + public class SessionLocator : ISessionLocator { + private readonly ISessionFactoryHolder _sessionFactoryHolder; + private readonly ITransactionManager _transactionManager; + private ISession _session; + + public SessionLocator( + ISessionFactoryHolder sessionFactoryHolder, + ITransactionManager transactionManager) { + _sessionFactoryHolder = sessionFactoryHolder; + _transactionManager = transactionManager; + } + + + public ISession For(Type entityType) { + if (_session==null) { + _transactionManager.Demand(); + var sessionFactory = _sessionFactoryHolder.GetSessionFactory(); + _session = sessionFactory.OpenSession(); + } + return _session; + } + + } +} \ No newline at end of file diff --git a/src/Orchard/Environment/DefaultOrchardHost.cs b/src/Orchard/Environment/DefaultOrchardHost.cs index 7070a484e..9175d1219 100644 --- a/src/Orchard/Environment/DefaultOrchardHost.cs +++ b/src/Orchard/Environment/DefaultOrchardHost.cs @@ -94,26 +94,27 @@ namespace Orchard.Environment { private IContainer CreateShellContainer(IShellSettings shellSettings) { foreach (var factory in _shellContainerFactories) { var container = factory.CreateContainer(shellSettings); - if (container != null) + if (container != null) { return container; + } } return null; } private void HackInstallSimulation() { - var tempContainer = CreateShellContainer(); - var containerProvider = new FiniteContainerProvider(tempContainer); - try { - var requestContainer = containerProvider.RequestContainer; + //var tempContainer = CreateShellContainer(); + //var containerProvider = new FiniteContainerProvider(tempContainer); + //try { + // var requestContainer = containerProvider.RequestContainer; - var hackInstallationGenerator = requestContainer.Resolve(); - hackInstallationGenerator.GenerateInstallEvents(); - } - finally { - // shut everything down again - containerProvider.DisposeRequestContainer(); - tempContainer.Dispose(); - } + // var hackInstallationGenerator = requestContainer.Resolve(); + // hackInstallationGenerator.GenerateInstallEvents(); + //} + //finally { + // // shut everything down again + // containerProvider.DisposeRequestContainer(); + // tempContainer.Dispose(); + //} } private void HackSimulateExtensionActivation(IContainer shellContainer) { diff --git a/src/Orchard/Environment/ShellBuilders/DefaultShellContainerFactory.cs b/src/Orchard/Environment/ShellBuilders/DefaultShellContainerFactory.cs index 587ef4b04..2609529f6 100644 --- a/src/Orchard/Environment/ShellBuilders/DefaultShellContainerFactory.cs +++ b/src/Orchard/Environment/ShellBuilders/DefaultShellContainerFactory.cs @@ -23,6 +23,7 @@ namespace Orchard.Environment.ShellBuilders { // add module types to container being built var addingModulesAndServices = new ContainerBuilder(); + addingModulesAndServices.Register(settings).As(); addingModulesAndServices.Register().As().SingletonScoped(); foreach (var moduleType in _compositionStrategy.GetModuleTypes()) { diff --git a/src/Orchard/Orchard.csproj b/src/Orchard/Orchard.csproj index a55116912..e105568a5 100644 --- a/src/Orchard/Orchard.csproj +++ b/src/Orchard/Orchard.csproj @@ -99,7 +99,7 @@ - + @@ -139,6 +139,7 @@ +