mirror of
https://github.com/OrchardCMS/Orchard.git
synced 2025-09-22 20:13:50 +08:00
Incremental progress on database work behind setup
--HG-- branch : dev
This commit is contained in:
@@ -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())
|
||||
|
@@ -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
|
||||
|
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
@@ -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();
|
||||
//}
|
||||
}
|
||||
}
|
||||
}
|
@@ -2,7 +2,7 @@ using System;
|
||||
using NHibernate;
|
||||
|
||||
namespace Orchard.Data {
|
||||
public interface ISessionLocator {
|
||||
public interface ISessionLocator : IDependency {
|
||||
ISession For(Type entityType);
|
||||
}
|
||||
}
|
@@ -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
|
||||
|
@@ -1,5 +1,5 @@
|
||||
namespace Orchard.Data.Migrations {
|
||||
public interface IDatabaseMigrationManager {
|
||||
public interface IDatabaseMigrationManager : IDependency {
|
||||
IDatabaseCoordinator CreateCoordinator(string provider, string dataFolder, string connectionString);
|
||||
}
|
||||
}
|
||||
|
@@ -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 {
|
||||
|
59
src/Orchard/Data/SessionFactoryHolder.cs
Normal file
59
src/Orchard/Data/SessionFactoryHolder.cs
Normal 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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
28
src/Orchard/Data/SessionLocator.cs
Normal file
28
src/Orchard/Data/SessionLocator.cs
Normal 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;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@@ -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) {
|
||||
|
@@ -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()) {
|
||||
|
@@ -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" />
|
||||
|
Reference in New Issue
Block a user