Refactoring database components

Simplifying for more direct use-cases

--HG--
branch : dev
This commit is contained in:
Louis DeJardin
2010-02-15 10:04:41 -08:00
parent ec5450ac2d
commit 3670374afc
11 changed files with 80 additions and 105 deletions

View File

@@ -64,22 +64,6 @@ namespace Orchard.Tests.Data.Migrations {
} }
[Test]
public void CanConnectShouldBeFalseWhenSqlServerIsInvalid() {
var manager = (IDatabaseMigrationManager)new DatabaseMigrationManager();
var coordinator = manager.CreateCoordinator("SqlServer", _tempDataFolder, "Data Source=.\\SQLEXPRESS;Initial Catalog=Hello");
Assert.That(coordinator.CanConnect(), Is.False);
}
[Test]
public void CanConnectShouldBeTrueWhenValidSqlServerMdfIsTargetted() {
var databasePath = Path.Combine(_tempDataFolder, "Orchard.mdf");
CreateSqlServerDatabase(databasePath);
var manager = (IDatabaseMigrationManager)new DatabaseMigrationManager();
var coordinator = manager.CreateCoordinator("SqlServer", _tempDataFolder, "Data Source=.\\SQLEXPRESS;AttachDbFileName=" + databasePath + ";Integrated Security=True;User Instance=True;");
Assert.That(coordinator.CanConnect(), Is.True);
}
[Test] [Test]
public void SQLiteSchemaShouldBeGeneratedAndUsable() { public void SQLiteSchemaShouldBeGeneratedAndUsable() {

View File

@@ -7,58 +7,34 @@ using FluentNHibernate.Cfg;
using FluentNHibernate.Cfg.Db; using FluentNHibernate.Cfg.Db;
using FluentNHibernate.Conventions.Helpers; using FluentNHibernate.Conventions.Helpers;
using NHibernate; using NHibernate;
using NHibernate.Cfg;
using NHibernate.Tool.hbm2ddl; using NHibernate.Tool.hbm2ddl;
using Orchard.ContentManagement.Records; using Orchard.ContentManagement.Records;
using Orchard.Data.Conventions; using Orchard.Data.Conventions;
using Orchard.Environment; using Orchard.Environment;
namespace Orchard.Data.Migrations { namespace Orchard.Data.Migrations {
public abstract class DatabaseCoordinatorBase : IDatabaseCoordinator { public abstract class AbstractSessionFactoryBuilder : ISessionFactoryBuilder {
protected abstract IPersistenceConfigurer GetPersistenceConfigurer(); protected abstract IPersistenceConfigurer GetPersistenceConfigurer();
public virtual bool CanConnect() { public ISessionFactory BuildSessionFactory(SessionFactoryBuilderParameters parameters) {
try { var database = GetPersistenceConfigurer();
var persistenceModel = CreatePersistenceModel(parameters.RecordDescriptors);
var sessionFactory = Fluently.Configure() var sessionFactory = Fluently.Configure()
.Database(GetPersistenceConfigurer()) .Database(database)
.Mappings(m => m.AutoMappings.Add(persistenceModel))
.ExposeConfiguration(config => Initialization(parameters, config))
.BuildSessionFactory(); .BuildSessionFactory();
try {
// attempting to open a session validates a connection can be made return sessionFactory;
var session = sessionFactory.OpenSession();
session.Close();
}
finally {
sessionFactory.Close();
}
return true;
}
catch {
return false;
}
} }
public virtual void CreateDatabase() { private static void Initialization(SessionFactoryBuilderParameters parameters, Configuration configuration) {
// creating a session factory appears to be sufficient for causing a database file to be created for inplace providers if (parameters.UpdateSchema) {
var sessionFactory = Fluently.Configure() var update = new SchemaUpdate(configuration);
.Database(GetPersistenceConfigurer()) update.Execute(false/*script*/, true /*doUpdate*/);
.BuildSessionFactory();
sessionFactory.Close();
} }
public void UpdateSchema(IEnumerable<RecordDescriptor> recordDescriptors) {
var configuration = Fluently.Configure()
.Database(GetPersistenceConfigurer())
.Mappings(m => m.AutoMappings.Add(CreatePersistenceModel(recordDescriptors)))
.BuildConfiguration();
var updater = new SchemaUpdate(configuration);
updater.Execute(true /*script*/, true /*doUpdate*/);
}
public ISessionFactory BuildSessionFactory(IEnumerable<RecordDescriptor> recordDescriptors) {
return Fluently.Configure()
.Database(GetPersistenceConfigurer())
.Mappings(m => m.AutoMappings.Add(CreatePersistenceModel(recordDescriptors)))
.BuildSessionFactory();
} }
public static AutoPersistenceModel CreatePersistenceModel(IEnumerable<RecordDescriptor> recordDescriptors) { public static AutoPersistenceModel CreatePersistenceModel(IEnumerable<RecordDescriptor> recordDescriptors) {
@@ -84,5 +60,6 @@ namespace Orchard.Data.Migrations {
public IEnumerable<Type> GetTypes() { return _recordDescriptors.Select(descriptor => descriptor.Type); } public IEnumerable<Type> GetTypes() { return _recordDescriptors.Select(descriptor => descriptor.Type); }
} }
} }
} }

View File

@@ -0,0 +1,11 @@
using System;
namespace Orchard.Data.Migrations {
public class DatabaseManager : IDatabaseManager {
public ISessionFactoryBuilder CreateCoordinator(string provider, string dataFolder, string connectionString) {
if (string.Equals(provider, "SQLite", StringComparison.InvariantCultureIgnoreCase))
return new SQLiteSessionFactoryBuilder(dataFolder, connectionString);
return new SqlServerSessionFactoryBuilder(dataFolder, connectionString);
}
}
}

View File

@@ -1,11 +0,0 @@
using System;
namespace Orchard.Data.Migrations {
public class DatabaseMigrationManager : IDatabaseMigrationManager {
public IDatabaseCoordinator CreateCoordinator(string provider, string dataFolder, string connectionString) {
if (string.Equals(provider, "SQLite", StringComparison.InvariantCultureIgnoreCase))
return new SQLiteDatabaseCoordinator(dataFolder, connectionString);
return new SqlServerDatabaseCoordinator(dataFolder, connectionString);
}
}
}

View File

@@ -1,19 +0,0 @@
using System.Collections.Generic;
using NHibernate;
using Orchard.Environment;
namespace Orchard.Data.Migrations {
public interface IDatabaseCoordinator {
bool CanConnect();
void CreateDatabase();
/// <summary>
/// Should only be called in a development or evaluation environment. Automatic schema migration
/// not a really safe practice on production data sources.
/// </summary>
/// <param name="recordDescriptors">Set of known records to be applied</param>
void UpdateSchema(IEnumerable<RecordDescriptor> recordDescriptors);
ISessionFactory BuildSessionFactory(IEnumerable<RecordDescriptor> recordDescriptors);
}
}

View File

@@ -0,0 +1,12 @@
namespace Orchard.Data.Migrations {
public interface IDatabaseManager : IDependency {
ISessionFactoryBuilder CreateCoordinator(DatabaseParameters databaseParameters);
}
public class DatabaseParameters {
public string Provider { get; set; }
public string DataFolder { get; set; }
public string ConnectionString { get; set; }
}
}

View File

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

View File

@@ -0,0 +1,15 @@
using System.Collections.Generic;
using NHibernate;
using Orchard.Environment;
namespace Orchard.Data.Migrations {
public interface ISessionFactoryBuilder {
ISessionFactory BuildSessionFactory(SessionFactoryBuilderParameters parameters);
}
public class SessionFactoryBuilderParameters {
public IEnumerable<RecordDescriptor> RecordDescriptors { get; set; }
public bool CreateDatabase { get; set; }
public bool UpdateSchema { get; set; }
}
}

View File

@@ -14,45 +14,56 @@ namespace Orchard.Data {
public class SessionFactoryHolder : ISessionFactoryHolder { public class SessionFactoryHolder : ISessionFactoryHolder {
private readonly IShellSettings _shellSettings; private readonly IShellSettings _shellSettings;
private readonly ICompositionStrategy _compositionStrategy; private readonly ICompositionStrategy _compositionStrategy;
private readonly IDatabaseMigrationManager _databaseMigrationManager; private readonly IDatabaseManager _databaseManager;
private ISessionFactory _sessionFactory; private ISessionFactory _sessionFactory;
public SessionFactoryHolder( public SessionFactoryHolder(
IShellSettings shellSettings, IShellSettings shellSettings,
ICompositionStrategy compositionStrategy, ICompositionStrategy compositionStrategy,
IDatabaseMigrationManager databaseMigrationManager) { IDatabaseManager databaseManager) {
_shellSettings = shellSettings; _shellSettings = shellSettings;
_compositionStrategy = compositionStrategy; _compositionStrategy = compositionStrategy;
_databaseMigrationManager = databaseMigrationManager; _databaseManager = databaseManager;
} }
public void UpdateSchema() { public void UpdateSchema() {
var coordinator = GetDatabaseCoordinator(); lock (this) {
coordinator.UpdateSchema(_compositionStrategy.GetRecordDescriptors()); if (_sessionFactory == null) {
_sessionFactory = BuildSessionFactory(true);
}
}
} }
public ISessionFactory GetSessionFactory() { public ISessionFactory GetSessionFactory() {
lock (this) { lock (this) {
if (_sessionFactory == null) { if (_sessionFactory == null) {
_sessionFactory = BuildSessionFactory(); _sessionFactory = BuildSessionFactory(false);
} }
} }
return _sessionFactory; return _sessionFactory;
} }
private ISessionFactory BuildSessionFactory() { private ISessionFactory BuildSessionFactory(bool updateSchema) {
var coordinator = GetDatabaseCoordinator();
return coordinator.BuildSessionFactory(_compositionStrategy.GetRecordDescriptors());
}
private IDatabaseCoordinator GetDatabaseCoordinator() {
var sitesPath = HostingEnvironment.MapPath("~/App_Data/Sites"); var sitesPath = HostingEnvironment.MapPath("~/App_Data/Sites");
var shellPath = Path.Combine(sitesPath, _shellSettings.Name); var shellPath = Path.Combine(sitesPath, _shellSettings.Name);
return _databaseMigrationManager.CreateCoordinator(_shellSettings.DataProvider, shellPath, _shellSettings.DataConnectionString);
var coordinator = _databaseManager.CreateCoordinator(new DatabaseParameters {
Provider = _shellSettings.DataProvider,
DataFolder = shellPath,
ConnectionString = _shellSettings.DataConnectionString
});
var sessionFactory = coordinator.BuildSessionFactory(new SessionFactoryBuilderParameters {
CreateDatabase = false,
UpdateSchema = updateSchema,
RecordDescriptors = _compositionStrategy.GetRecordDescriptors()
});
return sessionFactory;
} }
} }