Incremental progress on database work behind setup

--HG--
branch : dev
This commit is contained in:
Louis DeJardin
2010-02-11 18:14:13 -08:00
parent 04aa71bc18
commit ec5450ac2d
13 changed files with 118 additions and 123 deletions

View File

@@ -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<DataModule>();
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())

View File

@@ -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<ISessionFactoryHolder>();
sessionFactoryHolder.UpdateSchema();
var contentManager = finiteEnvironment.Resolve<IContentManager>();
// create superuser

View File

@@ -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<HackSessionLocator>().As<ISessionLocator>().ContainerScoped();
}
}
}

View File

@@ -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<RecordDescriptor> 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<RecordDescriptor> 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<DataModule>();
alt.Add(new ContentItemAlteration(recordDescriptors));
})
.Conventions.AddFromAssemblyOf<DataModule>();
}
private class TypeSource : ITypeSource {
private readonly IEnumerable<Type> _recordTypes;
public TypeSource(IEnumerable<Type> recordTypes) {
_recordTypes = recordTypes;
}
public IEnumerable<Type> 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();
//}
}
}
}

View File

@@ -2,7 +2,7 @@ using System;
using NHibernate;
namespace Orchard.Data {
public interface ISessionLocator {
public interface ISessionLocator : IDependency {
ISession For(Type entityType);
}
}

View File

@@ -61,7 +61,7 @@ namespace Orchard.Data.Migrations {
.BuildSessionFactory();
}
static AutoPersistenceModel CreatePersistenceModel(IEnumerable<RecordDescriptor> recordDescriptors) {
public static AutoPersistenceModel CreatePersistenceModel(IEnumerable<RecordDescriptor> 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

View File

@@ -1,5 +1,5 @@
namespace Orchard.Data.Migrations {
public interface IDatabaseMigrationManager {
public interface IDatabaseMigrationManager : IDependency {
IDatabaseCoordinator CreateCoordinator(string provider, string dataFolder, string connectionString);
}
}

View File

@@ -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 {

View File

@@ -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);
}
}
}

View File

@@ -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;
}
}
}

View File

@@ -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<IHackInstallationGenerator>();
hackInstallationGenerator.GenerateInstallEvents();
}
finally {
// shut everything down again
containerProvider.DisposeRequestContainer();
tempContainer.Dispose();
}
// var hackInstallationGenerator = requestContainer.Resolve<IHackInstallationGenerator>();
// hackInstallationGenerator.GenerateInstallEvents();
//}
//finally {
// // shut everything down again
// containerProvider.DisposeRequestContainer();
// tempContainer.Dispose();
//}
}
private void HackSimulateExtensionActivation(IContainer shellContainer) {

View File

@@ -23,6 +23,7 @@ namespace Orchard.Environment.ShellBuilders {
// add module types to container being built
var addingModulesAndServices = new ContainerBuilder();
addingModulesAndServices.Register(settings).As<IShellSettings>();
addingModulesAndServices.Register<DefaultOrchardShell>().As<IOrchardShell>().SingletonScoped();
foreach (var moduleType in _compositionStrategy.GetModuleTypes()) {

View File

@@ -99,7 +99,7 @@
</Reference>
</ItemGroup>
<ItemGroup>
<Compile Include="Data\HackSessionLocator.cs" />
<Compile Include="Data\SessionLocator.cs" />
<Compile Include="Data\IRepository.cs" />
<Compile Include="Data\ISessionLocator.cs" />
<Compile Include="Data\DataModule.cs" />
@@ -139,6 +139,7 @@
<Compile Include="Data\Migrations\IDatabaseMigrationManager.cs" />
<Compile Include="Data\Migrations\SQLiteDatabaseCoordinator.cs" />
<Compile Include="Data\Migrations\SqlServerDatabaseCoordinator.cs" />
<Compile Include="Data\SessionFactoryHolder.cs" />
<Compile Include="Environment\Configuration\ShellSettingsLoader.cs" />
<Compile Include="Environment\ExtensibleInterceptionModule.cs" />
<Compile Include="Environment\ShellBuilders\DefaultShellContainerFactory.cs" />