--HG--
branch : dev
This commit is contained in:
Louis DeJardin
2010-07-06 18:58:21 -07:00
37 changed files with 602 additions and 188 deletions

View File

@@ -12,7 +12,7 @@ namespace Orchard.Specs.Hosting {
class TraceEnabledBuilder : SQLiteDataServicesProvider {
public TraceEnabledBuilder(string dataFolder, string connectionString) : base(dataFolder, connectionString) {
}
protected override IPersistenceConfigurer GetPersistenceConfigurer(bool createDatabase) {
public override IPersistenceConfigurer GetPersistenceConfigurer(bool createDatabase) {
var config = (SQLiteConfiguration)base.GetPersistenceConfigurer(createDatabase);
//config.ShowSql();
return config;

View File

@@ -64,12 +64,12 @@ namespace Orchard.Tests.Data.Builders {
var parameters = new SessionFactoryParameters {
Provider = "SQLite",
DataFolder = _tempDataFolder,
UpdateSchema = true,
RecordDescriptors = recordDescriptors
};
var sessionFactory = manager
.CreateProvider(parameters)
.BuildSessionFactory(parameters);
.BuildConfiguration(parameters)
.BuildSessionFactory();
var session = sessionFactory.OpenSession();
@@ -102,12 +102,12 @@ namespace Orchard.Tests.Data.Builders {
Provider = "SqlServer",
DataFolder = _tempDataFolder,
ConnectionString = "Data Source=.\\SQLEXPRESS;AttachDbFileName=" + databasePath + ";Integrated Security=True;User Instance=True;",
UpdateSchema = true,
RecordDescriptors = recordDescriptors,
};
var sessionFactory = manager
.CreateProvider(parameters)
.BuildSessionFactory(parameters);
.BuildConfiguration(parameters)
.BuildSessionFactory();

View File

@@ -59,7 +59,6 @@ namespace Orchard.Tests.DataMigration {
builder.RegisterInstance(_folders).As<IExtensionFolders>();
builder.RegisterType<ExtensionManager>().As<IExtensionManager>();
builder.RegisterType<DataMigrationManager>().As<IDataMigrationManager>();
builder.RegisterType<DefaultDataMigrationGenerator>().As<IDataMigrationGenerator>();
builder.RegisterGeneric(typeof(Repository<>)).As(typeof(IRepository<>));
_session = _sessionFactory.OpenSession();
builder.RegisterInstance(new DefaultContentManagerTests.TestSessionLocator(_session)).As<ISessionLocator>();

View File

@@ -1,5 +1,4 @@
using System.Data;
using System.Linq;
using Autofac;
using NHibernate;
using NUnit.Framework;

View File

@@ -18,10 +18,10 @@ namespace Orchard.Core.Contents {
public string MenuName { get { return "admin"; } }
public void GetNavigation(NavigationBuilder builder) {
var contentTypeDefinitions = _contentDefinitionManager.ListTypeDefinitions().OrderBy(d => d.Name);
//var contentTypeDefinitions = _contentDefinitionManager.ListTypeDefinitions().OrderBy(d => d.Name);
builder.Add(T("Content"), "1", menu => {
menu.Add(T("Manage Content"), "1.2", item => item.Action("List", "Admin", new {area = "Orchard.ContentTypes"}));
//builder.Add(T("Content"), "1", menu => {
// menu.Add(T("Manage Content"), "1.2", item => item.Action("List", "Admin", new {area = "Orchard.ContentTypes"}));
//foreach (var contentTypeDefinition in contentTypeDefinitions) {
// var ci = _contentManager.New(contentTypeDefinition.Name);
// var cim = _contentManager.GetItemMetadata(ci);
@@ -29,7 +29,7 @@ namespace Orchard.Core.Contents {
// if (createRouteValues.Any())
// menu.Add(T("Create New {0}", contentTypeDefinition.DisplayName), "1.3", item => item.Action(cim.CreateRouteValues["Action"] as string, cim.CreateRouteValues["Controller"] as string, cim.CreateRouteValues));
//}
});
//});
}
}
}

View File

@@ -1,11 +1,16 @@
using Orchard.UI.Navigation;
using Orchard.Localization;
using Orchard.UI.Navigation;
namespace Orchard.DevTools {
public class AdminMenu : INavigationProvider {
public string MenuName { get { return "admin"; } }
public Localizer T { get; set; }
public void GetNavigation(NavigationBuilder builder) {
builder.Add(T("Site Configuration"), "11",
menu => menu
.Add(T("Developer Tools"), "10.0", item => item.Action("Index", "Home", new { area = "Orchard.DevTools" })
));
}
}
}

View File

@@ -3,27 +3,72 @@ using System.IO;
using System.Linq;
using System.Web.Hosting;
using Orchard.Commands;
using Orchard.Data.Migration.Generator;
using Orchard.DevTools.Services;
using Orchard.Environment.Extensions;
namespace Orchard.DevTools.Commands {
[OrchardFeature("Scaffolding")]
public class ScaffoldingCommands : DefaultOrchardCommandHandler {
private readonly IExtensionManager _extensionManager;
private readonly ISchemaCommandGenerator _schemaCommandGenerator;
public ScaffoldingCommands(IExtensionManager extensionManager) {
public ScaffoldingCommands(IExtensionManager extensionManager,
ISchemaCommandGenerator schemaCommandGenerator) {
_extensionManager = extensionManager;
_schemaCommandGenerator = schemaCommandGenerator;
}
[OrchardSwitch]
public bool IncludeInSolution { get; set; }
[CommandHelp("scaffolding create datamigration <feature-name> \r\n\t" + "Create a new Data Migration class")]
[CommandName("scaffolding create datamigration")]
public void CreateDataMigration(string featureName) {
Context.Output.WriteLine(T("Creating Data Migration for {0}", featureName));
foreach ( var extension in _extensionManager.AvailableExtensions() ) {
if ( extension.ExtensionType == "Module" && extension.Features.Any(f => String.Equals(f.Name, featureName, StringComparison.OrdinalIgnoreCase)) ) {
string dataMigrationsPath = HostingEnvironment.MapPath("~/Modules/" + extension.Name + "/DataMigrations/");
string dataMigrationPath = dataMigrationsPath + extension.DisplayName + "DataMigration.cs";
string templatesPath = HostingEnvironment.MapPath("~/Modules/Orchard.DevTools/ScaffoldingTemplates/");
if ( !Directory.Exists(dataMigrationsPath) ) {
Directory.CreateDirectory(dataMigrationsPath);
}
if ( File.Exists(dataMigrationPath) ) {
Context.Output.WriteLine(T("Data migration already exists in target Module {0}.", extension.Name));
return;
}
var commands = _schemaCommandGenerator.GetCreateFeatureCommands(featureName, false).ToList();
var stringWriter = new StringWriter();
var interpreter = new ScaffoldingCommandInterpreter(stringWriter);
foreach ( var command in commands ) {
interpreter.Visit(command);
stringWriter.WriteLine();
}
string dataMigrationText = File.ReadAllText(templatesPath + "DataMigration.txt");
dataMigrationText = dataMigrationText.Replace("$$FeatureName$$", featureName);
dataMigrationText = dataMigrationText.Replace("$$ClassName$$", extension.DisplayName);
dataMigrationText = dataMigrationText.Replace("$$Commands$$", stringWriter.ToString());
File.WriteAllText(dataMigrationPath, dataMigrationText);
Context.Output.WriteLine(T("Data migration created successfully in Module {0}", extension.DisplayName));
return;
}
}
Context.Output.WriteLine(T("Creating data migration failed: target Feature {0} could not be found.", featureName));
}
[CommandHelp("scaffolding create module <module-name> [/IncludeInSolution:true|false]\r\n\t" + "Create a new Orchard module")]
[CommandName("scaffolding create module")]
[OrchardSwitches("IncludeInSolution")]
public void CreateModule(string moduleName) {
Context.Output.WriteLine(T("Creating Module {0}", moduleName));
if (_extensionManager.AvailableExtensions().Any(extension => extension.ExtensionType == "Module" && String.Equals(moduleName, extension.DisplayName, StringComparison.OrdinalIgnoreCase))) {
if ( _extensionManager.AvailableExtensions().Any(extension => extension.ExtensionType == "Module" && String.Equals(moduleName, extension.DisplayName, StringComparison.OrdinalIgnoreCase)) ) {
Context.Output.WriteLine(T("Creating Module {0} failed: a module of the same name already exists", moduleName));
return;
}

View File

@@ -0,0 +1,38 @@
using System;
using System.Web.Mvc;
using Orchard.Data.Migration.Generator;
using Orchard.Localization;
using Orchard.Mvc.ViewModels;
using Orchard.UI.Notify;
namespace Orchard.DevTools.Controllers {
[ValidateInput(false)]
public class DataMigrationController : Controller {
private readonly ISchemaCommandGenerator _schemaCommandGenerator;
public DataMigrationController(ISchemaCommandGenerator schemaCommandGenerator, IOrchardServices orchardServices) {
_schemaCommandGenerator = schemaCommandGenerator;
Services = orchardServices;
}
public IOrchardServices Services { get; set; }
public Localizer T { get; set; }
public ActionResult Index() {
return View(new BaseViewModel());
}
public ActionResult UpdateDatabase() {
try {
_schemaCommandGenerator.UpdateDatabase();
Services.Notifier.Information(T("Database updated successfuly"));
}
catch (Exception ex) {
Services.Notifier.Error(T("An error occured while updating the database: {0}", ex.Message));
}
return RedirectToAction("Index");
}
}
}

View File

@@ -74,6 +74,7 @@
<Compile Include="Commands\ScaffoldingCommands.cs" />
<Compile Include="Controllers\CommandsController.cs" />
<Compile Include="Controllers\ContentController.cs" />
<Compile Include="Controllers\DataMigrationController.cs" />
<Compile Include="Controllers\HomeController.cs" />
<Compile Include="Controllers\MetadataController.cs" />
<Compile Include="Handlers\DebugLinkHandler.cs" />
@@ -81,6 +82,8 @@
<Compile Include="Models\Simple.cs" />
<Compile Include="Permissions.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Content Include="ScaffoldingTemplates\DataMigration.txt" />
<Compile Include="Services\ScaffoldingCommandInterpreter.cs" />
<Compile Include="Settings\DevToolsSettings.cs" />
<Compile Include="ViewModels\CommandsExecuteViewModel.cs" />
<Compile Include="ViewModels\ContentIndexViewModel.cs" />
@@ -95,6 +98,7 @@
<Content Include="ScaffoldingTemplates\ModuleManifest.txt" />
<Content Include="ScaffoldingTemplates\ModuleWebConfig.txt" />
<Content Include="Views\Commands\Execute.ascx" />
<Content Include="Views\DataMigration\Index.aspx" />
<Content Include="Views\DefinitionTemplates\DevToolsSettings.ascx" />
<Content Include="Views\Home\_RenderableAction.ascx" />
<Content Include="Views\Home\Simple.aspx" />

View File

@@ -0,0 +1,13 @@
using System.Data;
using Orchard.Data.Migration;
namespace $$FeatureName$$.DataMigrations {
public class $$ClassName$$DataMigration : DataMigrationImpl {
public int Create() {
$$Commands$$
return 0100;
}
}
}

View File

@@ -0,0 +1,78 @@
using System.Collections.Generic;
using System.IO;
using System.Linq;
using Orchard.Data.Migration.Interpreters;
using Orchard.Data.Migration.Schema;
namespace Orchard.DevTools.Services {
public class ScaffoldingCommandInterpreter : AbstractDataMigrationInterpreter {
private readonly TextWriter _output;
public ScaffoldingCommandInterpreter(TextWriter output) {
_output = output;
}
public override void Visit(CreateTableCommand command) {
_output.WriteLine("// Creating table {0}", command.Name);
_output.WriteLine("\t\t\tSchemaBuilder.CreateTable(\"{0}\", table => table", command.Name);
foreach ( var createColumn in command.TableCommands.OfType<CreateColumnCommand>() ) {
var type = createColumn.DbType.ToString();
var field = createColumn.ColumnName;
var options = new List<string>();
if ( createColumn.IsPrimaryKey ) {
options.Add(string.Format("WithLength({0})", createColumn.Length));
}
if ( createColumn.IsUnique ) {
options.Add("Unique()");
}
if ( createColumn.IsNotNull ) {
options.Add("NotNull()");
}
if ( createColumn.IsPrimaryKey ) {
options.Add("PrimaryKey()");
}
if ( createColumn.Length.HasValue ) {
options.Add(string.Format("WithLength({0})", createColumn.Length ));
}
if ( createColumn.Precision > 0 ) {
options.Add(string.Format("WithPrecision({0})", createColumn.Precision));
options.Add(string.Format("WithScale({0})", createColumn.Scale));
}
_output.WriteLine("\t\t\t\t.Column(\"{0}\", DbType.{1}{2})", field, type, options.Any() ? ", column => column." + string.Join(".", options) : string.Empty);
}
_output.WriteLine("\t\t\t);");
}
public override void Visit(AlterTableCommand command) {
_output.WriteLine("// Altering table {0}", command.Name);
}
public override void Visit(DropTableCommand command) {
_output.WriteLine("// Dropping table {0}", command.Name);
_output.WriteLine("\t\t\tSchemaBuilder.DropTable(\"{0}\", command.Name);");
}
public override void Visit(SqlStatementCommand command) {
_output.WriteLine("// Executing sql statement\n\n {0}", command.Sql);
}
public override void Visit(CreateForeignKeyCommand command) {
_output.WriteLine("// Creating foreign key {0}", command.Name);
}
public override void Visit(DropForeignKeyCommand command) {
_output.WriteLine("// Dropping foreign key {0}", command.Name);
}
}
}

View File

@@ -0,0 +1,5 @@
<%@ Page Language="C#" Inherits="Orchard.Mvc.ViewPage<BaseViewModel>"%>
<%@ Import Namespace="Orchard.Mvc.ViewModels"%>
<h1><%: Html.TitleForPage(T("Data Migration").ToString()) %></h1>
<p><%: Html.ActionLink(T("Update Database").ToString(), "UpdateDatabase", "DataMigration") %></p>

View File

@@ -4,4 +4,4 @@
<p><%: Html.ActionLink(T("Contents").ToString(), "Index", "Content") %></p>
<p><%: Html.ActionLink(T("Metadata").ToString(), "Index", "Metadata") %></p>
<p><%: Html.ActionLink(T("Test Unauthorized Request").ToString(), "NotAuthorized", "Home")%></p>
<p><%: Html.ActionLink(T("Data migration").ToString(), "Index", "DataMigration")%></p>

View File

@@ -3,8 +3,6 @@ using System.Collections.Generic;
using System.Linq;
using Orchard.Commands;
using Orchard.ContentManagement;
using Orchard.Indexing;
using Orchard.Security;
using Orchard.Tasks.Indexing;
namespace Orchard.Indexing.Commands {

View File

@@ -5,7 +5,6 @@ namespace Orchard.Indexing.DataMigrations {
public class IndexingDataMigration : DataMigrationImpl {
public int Create() {
SchemaBuilder.CreateTable("IndexingTaskRecord", table => table
.Column<int>("Id", column => column.PrimaryKey())
.Column<int>("Action")

View File

@@ -2,6 +2,7 @@
using System.Linq;
using System.Web;
using System.Web.Mvc;
using Orchard.Data.Migration;
using Orchard.Localization;
using Orchard.Modules.ViewModels;
using Orchard.Mvc.Results;
@@ -11,10 +12,12 @@ using Orchard.Utility.Extensions;
namespace Orchard.Modules.Controllers {
public class AdminController : Controller {
private readonly IModuleService _moduleService;
private readonly IDataMigrationManager _dataMigrationManager;
public AdminController(IOrchardServices services, IModuleService moduleService) {
public AdminController(IOrchardServices services, IModuleService moduleService, IDataMigrationManager dataMigrationManager) {
Services = services;
_moduleService = moduleService;
_dataMigrationManager = dataMigrationManager;
T = NullLocalizer.Instance;
}
@@ -68,7 +71,9 @@ namespace Orchard.Modules.Controllers {
return new HttpUnauthorizedResult();
var features = _moduleService.GetAvailableFeatures().ToList();
return View(new FeaturesViewModel {Features = features});
var featuresThatNeedUpdate = _dataMigrationManager.GetFeaturesThatNeedUpdate();
return View(new FeaturesViewModel { Features = features, FeaturesThatNeedUpdate = featuresThatNeedUpdate });
}
[HttpPost]
@@ -96,5 +101,24 @@ namespace Orchard.Modules.Controllers {
return RedirectToAction("Features");
}
[HttpPost]
public ActionResult Update(string id, bool? force) {
if ( !Services.Authorizer.Authorize(Permissions.ManageFeatures, T("Not allowed to manage features")) )
return new HttpUnauthorizedResult();
if ( string.IsNullOrEmpty(id) )
return new NotFoundResult();
try {
_dataMigrationManager.Update(id);
Services.Notifier.Information(T("The feature {0} was updated succesfuly", id));
}
catch(Exception ex) {
Services.Notifier.Error(T("An error occured while updating the feature {0}: {1}", id, ex.Message));
}
return RedirectToAction("Features");
}
}
}

View File

@@ -4,5 +4,6 @@ using Orchard.Mvc.ViewModels;
namespace Orchard.Modules.ViewModels {
public class FeaturesViewModel : BaseViewModel {
public IEnumerable<IModuleFeature> Features { get; set; }
public IEnumerable<string> FeaturesThatNeedUpdate { get; set; }
}
}

View File

@@ -29,7 +29,7 @@
//hmmm...I feel like I've done this before...
var featureId = feature.Descriptor.Name.AsFeatureId(n => T(n));
var featureState = feature.IsEnabled ? "enabled" : "disabled";
var featureClassName = string.Format("feature {0}", featureState);
var featureClassName = string.Format("feature {0}", featureState + (Model.FeaturesThatNeedUpdate.Contains(feature.Descriptor.Name) ? " update" : String.Empty));
if (feature == features.First())
featureClassName += " first";
if (feature == features.Last())
@@ -65,7 +65,15 @@
<%: Html.Hidden("force", true)%>
<button type="submit"><%: T("Enable") %></button><%
}
} %>
}
if(Model.FeaturesThatNeedUpdate.Contains(feature.Descriptor.Name)){
using (Html.BeginFormAntiForgeryPost(string.Format("{0}", Url.Action("Update", new { area = "Orchard.Modules" })), FormMethod.Post, new {@class = "inline link"})) { %>
<%: Html.Hidden("id", feature.Descriptor.Name, new { id = "" })%>
<%: Html.Hidden("force", true)%>
<button type="submit" class="update"><%: T("Update") %></button><%
}
}
%>
</div><%
} %>
</div>

View File

@@ -110,6 +110,16 @@
top:.4em;
}
a.update {
margin-left:.5em;
}
.features .update.feature {
background:#ecc;
}
.features.summary-view .update.feature {
border-color:#e77;
}
.cathedral {
bottom:0;
font-size:.8em;
@@ -121,4 +131,4 @@
.cathedral a:visited,
.cathedral form.inline.link button {
color:#aeaeae;
}
}

View File

@@ -1,24 +1,33 @@
using System;
using System.Linq;
using Orchard.Commands;
using Orchard.Data.Migration.Generator;
using Orchard.Data.Migration.Interpreters;
namespace Orchard.Data.Migration.Commands {
public class DataMigrationCommands : DefaultOrchardCommandHandler {
private readonly IDataMigrationManager _dataMigrationManager;
private readonly IDataMigrationInterpreter _dataMigrationInterpreter;
private readonly ISchemaCommandGenerator _schemaCommandGenerator;
public DataMigrationCommands(
IDataMigrationManager dataMigrationManager) {
IDataMigrationManager dataMigrationManager,
IDataMigrationInterpreter dataMigrationInterpreter,
ISchemaCommandGenerator schemaCommandGenerator
) {
_dataMigrationManager = dataMigrationManager;
_dataMigrationInterpreter = dataMigrationInterpreter;
_schemaCommandGenerator = schemaCommandGenerator;
}
[OrchardSwitch]
public string Feature { get; set; }
public bool Drop { get; set; }
[CommandName("upgrade database")]
[CommandHelp("upgrade database /Feature:<feature> \r\n\t" + "Upgrades or create the database tables for the named <feature>")]
[OrchardSwitches("Feature")]
public string UpgradeDatabase() {
[CommandHelp("upgrade database <feature-name> \r\n\t" + "Upgrades or create the database tables for the <feature-name>")]
public string UpgradeDatabase(string featureName) {
try {
_dataMigrationManager.Update(Feature);
_dataMigrationManager.Update(featureName);
}
catch ( Exception ex ) {
Context.Output.WriteLine(T("An error occured while upgrading the database: " + ex.Message));
@@ -27,5 +36,45 @@ namespace Orchard.Data.Migration.Commands {
return "Database upgraded";
}
[CommandName("update database")]
[CommandHelp("update database \r\n\t" + "Automatically updates the database schema for the enabled features")]
public string UpdateDatabase() {
try {
_schemaCommandGenerator.UpdateDatabase();
}
catch ( Exception ex ) {
Context.Output.WriteLine(T("An error occured while updating the database: " + ex.Message));
return "Update terminated.";
}
return "Database updated";
}
[CommandName("create tables")]
[CommandHelp("create tables <feature-name> [/Drop:true|false] \r\n\t" + "Creates the database tables for the <feature-name> and optionaly drops them before if specified")]
[OrchardSwitches("Drop")]
public string CreateTables(string featureName) {
var stringInterpreter = new StringCommandInterpreter(Context.Output);
try {
var commands = _schemaCommandGenerator.GetCreateFeatureCommands(featureName, Drop).ToList();
if ( commands.Any() ) {
foreach (var command in commands) {
stringInterpreter.Visit(command);
_dataMigrationInterpreter.Visit(command);
}
}
else {
return "There are no tables to create for this feature.";
}
}
catch ( Exception ex ) {
Context.Output.WriteLine(T("An error occured while creating the tables: " + ex.Message));
return "Tables creation terminated.";
}
return "Tables created";
}
}
}

View File

@@ -24,11 +24,13 @@ namespace Orchard.Data.Migration {
IEnumerable<IDataMigration> dataMigrations,
IRepository<DataMigrationRecord> dataMigrationRepository,
IExtensionManager extensionManager,
IDataMigrationInterpreter interpreter) {
IDataMigrationInterpreter interpreter
) {
_dataMigrations = dataMigrations;
_dataMigrationRepository = dataMigrationRepository;
_extensionManager = extensionManager;
_interpreter = interpreter;
Logger = NullLogger.Instance;
}
@@ -93,7 +95,7 @@ namespace Orchard.Data.Migration {
var migrations = GetDataMigrations(feature);
// apply update methods to each migration class for the module
// apply update methods to each migration class for the module))))
foreach ( var migration in migrations ) {
// copy the objet for the Linq query
var tempMigration = migration;
@@ -149,7 +151,7 @@ namespace Orchard.Data.Migration {
// apply update methods to each migration class for the module
foreach (var migration in migrations) {
// copy the objet for the Linq query
// copy the object for the Linq query
var tempMigration = migration;
// get current version for this migration

View File

@@ -1,14 +0,0 @@
using System.Collections.Generic;
using System.Linq;
using Orchard.Data.Migration.Schema;
using Orchard.Environment.ShellBuilders.Models;
namespace Orchard.Data.Migration {
public class DefaultDataMigrationGenerator : IDataMigrationGenerator {
public IEnumerable<ISchemaBuilderCommand> CreateCommands(IEnumerable<RecordBlueprint> records) {
return Enumerable.Empty<ISchemaBuilderCommand>();
}
}
}

View File

@@ -0,0 +1,24 @@
using System.Collections.Generic;
using Orchard.Data.Migration.Schema;
namespace Orchard.Data.Migration.Generator {
public interface ISchemaCommandGenerator : IDependency {
/// <summary>
/// Returns a set of <see cref="SchemaCommand"/> instances to execute in order to create the tables requiered by the specified feature.
/// </summary>
/// <param name="feature">The name of the feature from which the tables need to be created.</param>
/// <param name="drop">Whether to generate drop commands for the created tables.</param>
IEnumerable<SchemaCommand> GetCreateFeatureCommands(string feature, bool drop);
/// <summary>
/// Automatically updates the tables in the database.
/// </summary>
void UpdateDatabase();
/// <summary>
/// Creates the tables in the database.
/// </summary>
void CreateDatabase();
}
}

View File

@@ -0,0 +1,95 @@
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using NHibernate.Cfg;
using NHibernate.Mapping;
using NHibernate.Tool.hbm2ddl;
using Orchard.Data.Migration.Schema;
using Orchard.Data.Providers;
using NHibernate.Dialect;
namespace Orchard.Data.Migration.Generator {
public class SchemaCommandGenerator : ISchemaCommandGenerator {
private readonly IDataServicesProviderFactory _dataServicesProviderFactory;
private readonly ISessionFactoryHolder _sessionFactoryHolder;
public SchemaCommandGenerator(
IDataServicesProviderFactory dataServicesProviderFactory,
ISessionFactoryHolder sessionFactoryHolder) {
_dataServicesProviderFactory = dataServicesProviderFactory;
_sessionFactoryHolder = sessionFactoryHolder;
}
public IEnumerable<SchemaCommand> GetCreateFeatureCommands(string feature, bool drop) {
var parameters = _sessionFactoryHolder.GetSessionFactoryParameters();
if (!parameters.RecordDescriptors.Any()) {
yield break;
}
var configuration = _dataServicesProviderFactory.CreateProvider(parameters).BuildConfiguration(parameters);
Dialect.GetDialect(configuration.Properties);
var mapping = configuration.BuildMapping();
// get the tables using reflection
var tablesField = typeof(Configuration).GetField("tables", BindingFlags.Instance | BindingFlags.NonPublic);
var tables = ((IDictionary<string, Table>) tablesField.GetValue(configuration)).Values;
foreach(var table in tables.Where(t => parameters.RecordDescriptors.Any(rd => rd.Feature.Descriptor.Name == feature && rd.TableName == t.Name))) {
if(drop) {
yield return new DropTableCommand(table.Name);
}
var command = new CreateTableCommand(table.Name);
foreach(var column in table.ColumnIterator) {
var table1 = table;
var column1 = column;
var sqlType = column1.GetSqlTypeCode(mapping);
command.Column(column.Name, sqlType.DbType,
action => {
if (table1.PrimaryKey.Columns.Any(c => c.Name == column1.Name)) {
action.PrimaryKey();
}
if (column1.IsLengthDefined()) {
action.WithLength(column1.Length);
}
if (column1.IsPrecisionDefined()) {
action.WithPrecision((byte) column1.Precision);
action.WithScale((byte) column1.Scale);
}
if (column1.IsNullable) {
action.Nullable();
}
if ( column1.IsUnique ) {
action.Unique();
}
if(column1.DefaultValue != null) {
action.WithDefault(column1.DefaultValue);
}
});
}
yield return command;
}
}
public void UpdateDatabase() {
var parameters = _sessionFactoryHolder.GetSessionFactoryParameters();
var configuration = _dataServicesProviderFactory.CreateProvider(parameters).BuildConfiguration(parameters);
new SchemaUpdate(configuration).Execute(false, true);
}
public void CreateDatabase() {
var parameters = _sessionFactoryHolder.GetSessionFactoryParameters();
var configuration = _dataServicesProviderFactory.CreateProvider(parameters).BuildConfiguration(parameters);
new SchemaExport(configuration).Execute(false, true, false);
}
}
}

View File

@@ -1,11 +0,0 @@
using System.Collections.Generic;
using FluentNHibernate.Cfg;
using Orchard.Data.Migration.Schema;
using Orchard.Environment.ShellBuilders.Models;
namespace Orchard.Data.Migration {
// Builds and runs the representative migration create calls
public interface IDataMigrationGenerator : IDependency {
IEnumerable<ISchemaBuilderCommand> CreateCommands(IEnumerable<RecordBlueprint> records);
}
}

View File

@@ -0,0 +1,41 @@
using Orchard.Data.Migration.Schema;
namespace Orchard.Data.Migration.Interpreters {
public abstract class AbstractDataMigrationInterpreter {
public void Visit(ISchemaBuilderCommand command) {
var schemaCommand = command as SchemaCommand;
if (schemaCommand == null) {
return;
}
switch ( schemaCommand.Type ) {
case SchemaCommandType.CreateTable:
Visit((CreateTableCommand)schemaCommand);
break;
case SchemaCommandType.AlterTable:
Visit((AlterTableCommand)schemaCommand);
break;
case SchemaCommandType.DropTable:
Visit((DropTableCommand)schemaCommand);
break;
case SchemaCommandType.SqlStatement:
Visit((SqlStatementCommand)schemaCommand);
break;
case SchemaCommandType.CreateForeignKey:
Visit((CreateForeignKeyCommand)schemaCommand);
break;
case SchemaCommandType.DropForeignKey:
Visit((DropForeignKeyCommand)schemaCommand);
break;
}
}
public abstract void Visit(CreateTableCommand command);
public abstract void Visit(AlterTableCommand command);
public abstract void Visit(DropTableCommand command);
public abstract void Visit(SqlStatementCommand command);
public abstract void Visit(CreateForeignKeyCommand command);
public abstract void Visit(DropForeignKeyCommand command);
}
}

View File

@@ -7,25 +7,40 @@ using NHibernate;
using NHibernate.Dialect;
using NHibernate.SqlTypes;
using Orchard.Data.Migration.Schema;
using Orchard.Data.Providers;
using Orchard.Environment.Configuration;
using Orchard.Logging;
namespace Orchard.Data.Migration.Interpreters {
public class DefaultDataMigrationInterpreter : IDataMigrationInterpreter {
public class DefaultDataMigrationInterpreter : AbstractDataMigrationInterpreter, IDataMigrationInterpreter {
private readonly ShellSettings _shellSettings;
private readonly IEnumerable<ICommandInterpreter> _commandInterpreters;
private readonly ISession _session;
private readonly Dialect _dialect;
private readonly List<string> _sqlStatements;
private readonly IDataServicesProviderFactory _dataServicesProviderFactory;
private readonly ISessionFactoryHolder _sessionFactoryHolder;
private const char Space = ' ' ;
public DefaultDataMigrationInterpreter(ShellSettings shellSettings, ISessionLocator sessionLocator, IEnumerable<ICommandInterpreter> commandInterpreters) {
public DefaultDataMigrationInterpreter(
ShellSettings shellSettings,
ISessionLocator sessionLocator,
IEnumerable<ICommandInterpreter> commandInterpreters,
IDataServicesProviderFactory dataServicesProviderFactory,
ISessionFactoryHolder sessionFactoryHolder) {
_shellSettings = shellSettings;
_commandInterpreters = commandInterpreters;
_session = sessionLocator.For(typeof(DefaultDataMigrationInterpreter));
_sqlStatements = new List<string>();
_dialect = _shellSettings.DataProvider == "SQLite" ? (Dialect) new SQLiteDialect() : new MsSql2008Dialect();
_dataServicesProviderFactory = dataServicesProviderFactory;
_sessionFactoryHolder = sessionFactoryHolder;
Logger = NullLogger.Instance;
var parameters = _sessionFactoryHolder.GetSessionFactoryParameters();
var configuration = _dataServicesProviderFactory.CreateProvider(parameters).BuildConfiguration(parameters);
_dialect = Dialect.GetDialect(configuration.Properties);
}
public ILogger Logger { get; set; }
@@ -34,35 +49,7 @@ namespace Orchard.Data.Migration.Interpreters {
get { return _sqlStatements; }
}
public void Visit(ISchemaBuilderCommand command) {
var schemaCommand = command as SchemaCommand;
if (schemaCommand == null) {
return;
}
switch ( schemaCommand.Type ) {
case SchemaCommandType.CreateTable:
Visit((CreateTableCommand)schemaCommand);
break;
case SchemaCommandType.AlterTable:
Visit((AlterTableCommand)schemaCommand);
break;
case SchemaCommandType.DropTable:
Visit((DropTableCommand)schemaCommand);
break;
case SchemaCommandType.SqlStatement:
Visit((SqlStatementCommand)schemaCommand);
break;
case SchemaCommandType.CreateForeignKey:
Visit((CreateForeignKeyCommand)schemaCommand);
break;
case SchemaCommandType.DropForeignKey:
Visit((DropForeignKeyCommand)schemaCommand);
break;
}
}
public void Visit(CreateTableCommand command) {
public override void Visit(CreateTableCommand command) {
if ( ExecuteCustomInterpreter(command) ) {
return;
@@ -103,7 +90,7 @@ namespace Orchard.Data.Migration.Interpreters {
RunPendingStatements();
}
public void Visit(DropTableCommand command) {
public override void Visit(DropTableCommand command) {
if ( ExecuteCustomInterpreter(command) ) {
return;
}
@@ -116,7 +103,7 @@ namespace Orchard.Data.Migration.Interpreters {
RunPendingStatements();
}
public void Visit(AlterTableCommand command) {
public override void Visit(AlterTableCommand command) {
if ( ExecuteCustomInterpreter(command) ) {
return;
}
@@ -229,18 +216,21 @@ namespace Orchard.Data.Migration.Interpreters {
_dialect.QuoteForColumnName(command.IndexName));
_sqlStatements.Add(builder.ToString());
}
public void Visit(SqlStatementCommand command) {
if (command.Providers.Count == 0 || command.Providers.Contains(_shellSettings.DataProvider) ) {
if (ExecuteCustomInterpreter(command)) {
return;
}
_sqlStatements.Add(command.Sql);
RunPendingStatements();
public override void Visit(SqlStatementCommand command) {
if (command.Providers.Count != 0 && !command.Providers.Contains(_shellSettings.DataProvider)) {
return;
}
if (ExecuteCustomInterpreter(command)) {
return;
}
_sqlStatements.Add(command.Sql);
RunPendingStatements();
}
public void Visit(CreateForeignKeyCommand command) {
public override void Visit(CreateForeignKeyCommand command) {
if ( ExecuteCustomInterpreter(command) ) {
return;
}
@@ -261,7 +251,7 @@ namespace Orchard.Data.Migration.Interpreters {
RunPendingStatements();
}
public void Visit(DropForeignKeyCommand command) {
public override void Visit(DropForeignKeyCommand command) {
if ( ExecuteCustomInterpreter(command) ) {
return;
}

View File

@@ -0,0 +1,36 @@
using System.IO;
using Orchard.Data.Migration.Schema;
namespace Orchard.Data.Migration.Interpreters {
public class StringCommandInterpreter : AbstractDataMigrationInterpreter {
private readonly TextWriter _output;
public StringCommandInterpreter(TextWriter output) {
_output = output;
}
public override void Visit(CreateTableCommand command) {
_output.WriteLine("Creating table {0}", command.Name);
}
public override void Visit(AlterTableCommand command) {
_output.WriteLine("Altering table {0}", command.Name);
}
public override void Visit(DropTableCommand command) {
_output.WriteLine("Dropping table {0}", command.Name);
}
public override void Visit(SqlStatementCommand command) {
_output.WriteLine("Executing sql statement\n\n {0}", command.Sql);
}
public override void Visit(CreateForeignKeyCommand command) {
_output.WriteLine("Creating foreign key {0}", command.Name);
}
public override void Visit(DropForeignKeyCommand command) {
_output.WriteLine("Dropping foreign key {0}", command.Name);
}
}
}

View File

@@ -19,25 +19,7 @@ namespace Orchard.Data.Migration.Schema {
}
public CreateTableCommand Column<T>(string columnName, Action<CreateColumnCommand> column = null) {
var dbType = System.Data.DbType.Object;
switch(System.Type.GetTypeCode(typeof(T))) {
case TypeCode.String :
dbType = DbType.String;
break;
case TypeCode.Int32:
dbType = DbType.Int32;
break;
case TypeCode.DateTime:
dbType = DbType.DateTime;
break;
case TypeCode.Boolean:
dbType = DbType.Boolean;
break;
default:
Enum.TryParse(System.Type.GetTypeCode(typeof (T)).ToString(), true, out dbType);
break;
}
var dbType = SchemaUtils.ToDbType(typeof (T));
return Column(columnName, dbType, column);
}
@@ -50,5 +32,7 @@ namespace Orchard.Data.Migration.Schema {
/// TODO: Call Column() with necessary information for content part records
return this;
}
}
}

View File

@@ -0,0 +1,30 @@
using System;
using System.Data;
namespace Orchard.Data.Migration.Schema {
public static class SchemaUtils {
public static DbType ToDbType(Type type) {
DbType dbType;
switch ( System.Type.GetTypeCode(type) ) {
case TypeCode.String:
dbType = DbType.String;
break;
case TypeCode.Int32:
dbType = DbType.Int32;
break;
case TypeCode.DateTime:
dbType = DbType.DateTime;
break;
case TypeCode.Boolean:
dbType = DbType.Boolean;
break;
default:
Enum.TryParse(Type.GetTypeCode(type).ToString(), true, out dbType);
break;
}
return dbType;
}
}
}

View File

@@ -16,30 +16,16 @@ using Orchard.Environment.ShellBuilders.Models;
namespace Orchard.Data.Providers {
public abstract class AbstractDataServicesProvider : IDataServicesProvider {
protected abstract IPersistenceConfigurer GetPersistenceConfigurer(bool createDatabase);
public abstract IPersistenceConfigurer GetPersistenceConfigurer(bool createDatabase);
public ISessionFactory BuildSessionFactory(SessionFactoryParameters parameters) {
public Configuration BuildConfiguration(SessionFactoryParameters parameters) {
var database = GetPersistenceConfigurer(parameters.CreateDatabase);
var persistenceModel = CreatePersistenceModel(parameters.RecordDescriptors);
var sessionFactory = Fluently.Configure()
return Fluently.Configure()
.Database(database)
.Mappings(m => m.AutoMappings.Add(persistenceModel))
.ExposeConfiguration(config => Initialization(parameters, config))
.BuildSessionFactory();
return sessionFactory;
}
private static void Initialization(SessionFactoryParameters parameters, Configuration configuration) {
if (parameters.CreateDatabase) {
var export = new SchemaExport(configuration);
export.Execute(false/*script*/, true/*export*/, false/*justDrop*/);
}
else if (parameters.UpdateSchema) {
var update = new SchemaUpdate(configuration);
update.Execute(false/*script*/, true /*doUpdate*/);
}
.BuildConfiguration();
}
public static AutoPersistenceModel CreatePersistenceModel(IEnumerable<RecordBlueprint> recordDescriptors) {
@@ -65,8 +51,5 @@ namespace Orchard.Data.Providers {
public IEnumerable<Type> GetTypes() { return _recordDescriptors.Select(descriptor => descriptor.Type); }
}
}
}

View File

@@ -1,10 +1,12 @@
using System;
using FluentNHibernate.Cfg;
using FluentNHibernate.Cfg.Db;
using NHibernate;
using NHibernate.Cfg;
namespace Orchard.Data.Providers {
public interface IDataServicesProvider : ITransientDependency {
ISessionFactory BuildSessionFactory(SessionFactoryParameters sessionFactoryParameters);
Configuration BuildConfiguration(SessionFactoryParameters sessionFactoryParameters);
IPersistenceConfigurer GetPersistenceConfigurer(bool createDatabase);
}
}

View File

@@ -15,7 +15,7 @@ namespace Orchard.Data.Providers {
get { return "SQLite"; }
}
protected override IPersistenceConfigurer GetPersistenceConfigurer(bool createDatabase) {
public override IPersistenceConfigurer GetPersistenceConfigurer(bool createDatabase) {
var persistence = SQLiteConfiguration.Standard;
if (string.IsNullOrEmpty(_connectionString)) {
var dataFile = Path.Combine(_dataFolder, "Orchard.db");

View File

@@ -5,6 +5,5 @@ namespace Orchard.Data.Providers {
public class SessionFactoryParameters : DataServiceParameters {
public IEnumerable<RecordBlueprint> RecordDescriptors { get; set; }
public bool CreateDatabase { get; set; }
public bool UpdateSchema { get; set; }
}
}

View File

@@ -16,7 +16,7 @@ namespace Orchard.Data.Providers {
get { return "SqlServer"; }
}
protected override IPersistenceConfigurer GetPersistenceConfigurer(bool createDatabase) {
public override IPersistenceConfigurer GetPersistenceConfigurer(bool createDatabase) {
var persistence = MsSqlConfiguration.MsSql2008;
if (string.IsNullOrEmpty(_connectionString)) {
throw new NotImplementedException();

View File

@@ -1,10 +1,6 @@
using System;
using System.IO;
using NHibernate;
using NHibernate;
using Orchard.Data.Providers;
using Orchard.Environment.Configuration;
using Orchard.Environment.Descriptor;
using Orchard.Environment.Descriptor.Models;
using Orchard.Environment.ShellBuilders.Models;
using Orchard.FileSystems.AppData;
using Orchard.Localization;
@@ -13,8 +9,7 @@ using Orchard.Logging;
namespace Orchard.Data {
public interface ISessionFactoryHolder : ISingletonDependency {
ISessionFactory GetSessionFactory();
void CreateDatabase();
void UpdateSchema();
SessionFactoryParameters GetSessionFactoryParameters();
}
public class SessionFactoryHolder : ISessionFactoryHolder {
@@ -42,61 +37,41 @@ namespace Orchard.Data {
public Localizer T { get; set; }
public ILogger Logger { get; set; }
public void CreateDatabase() {
lock (this) {
if (_sessionFactory != null) {
Logger.Error("CreateSchema can not be called after a session factory was created");
throw new OrchardCoreException(T("CreateSchema can not be called after a session factory was created"));
}
_sessionFactory = BuildSessionFactory(true /*createDatabase*/, false /*updateSchema*/);
}
}
public void UpdateSchema() {
lock (this) {
if (_sessionFactory != null) {
Logger.Error("UpdateSchema can not be called after a session factory was created");
throw new OrchardCoreException(T("UpdateSchema can not be called after a session factory was created"));
}
_sessionFactory = BuildSessionFactory(false /*createDatabase*/, true /*updateSchema*/);
}
}
public ISessionFactory GetSessionFactory() {
lock (this) {
if (_sessionFactory == null) {
_sessionFactory = BuildSessionFactory(false /*createDatabase*/, false /*updateSchema*/);
_sessionFactory = BuildSessionFactory();
}
}
return _sessionFactory;
}
private ISessionFactory BuildSessionFactory(bool createDatabase, bool updateSchema) {
private ISessionFactory BuildSessionFactory() {
Logger.Debug("Building session factory");
var parameters = GetSessionFactoryParameters();
var sessionFactory = _dataServicesProviderFactory
.CreateProvider(parameters)
.BuildConfiguration(parameters)
.BuildSessionFactory();
return sessionFactory;
}
public SessionFactoryParameters GetSessionFactoryParameters() {
var shellPath = _appDataFolder.Combine("Sites", _shellSettings.Name);
_appDataFolder.CreateDirectory(shellPath);
var shellFolder = _appDataFolder.MapPath(shellPath);
var parameters = new SessionFactoryParameters {
return new SessionFactoryParameters {
Provider = _shellSettings.DataProvider,
DataFolder = shellFolder,
ConnectionString = _shellSettings.DataConnectionString,
CreateDatabase = createDatabase,
UpdateSchema = updateSchema,
RecordDescriptors = _shellBlueprint.Records,
};
var sessionFactory = _dataServicesProviderFactory
.CreateProvider(parameters)
.BuildSessionFactory(parameters);
return sessionFactory;
}
}

View File

@@ -359,13 +359,18 @@
<SubType>Code</SubType>
</Compile>
<Compile Include="ContentManagement\DataMigrations\FrameworkDataMigration.cs" />
<Compile Include="Data\Migration\Generator\ISchemaCommandGenerator.cs" />
<Compile Include="Data\Migration\Interpreters\AbstractDataMigrationInterpreter.cs" />
<Compile Include="Data\Migration\Interpreters\ICommandInterpreter.cs" />
<Compile Include="Data\Migration\Interpreters\DefaultDataMigrationInterpreter.cs" />
<Compile Include="Data\Migration\Interpreters\IDataMigrationInterpreter.cs" />
<Compile Include="Data\Migration\Interpreters\SqLiteCommandInterpreter.cs" />
<Compile Include="Data\Migration\Interpreters\StringCommandInterpreter.cs" />
<Compile Include="Data\Migration\Schema\AddColumnCommand.cs" />
<Compile Include="Data\Migration\Schema\ISchemaBuilderCommand.cs" />
<Compile Include="Data\Migration\Schema\IShellSettings.cs" />
<Compile Include="Data\Migration\Generator\SchemaCommandGenerator.cs" />
<Compile Include="Data\Migration\Schema\SchemaUtils.cs" />
<Compile Include="Data\Migration\Schema\SqlStatementCommand.cs" />
<Compile Include="Data\Migration\Schema\CreateColumnCommand.cs" />
<Compile Include="Data\Migration\Schema\CreateForeignKeyCommand.cs" />
@@ -379,8 +384,6 @@
<Compile Include="Data\Migration\Commands\DataMigrationCommands.cs" />
<Compile Include="Data\Migration\Schema\SchemaBuilder.cs" />
<Compile Include="Data\Migration\DataMigrationCoordinator.cs" />
<Compile Include="Data\Migration\DefaultDataMigrationGenerator.cs" />
<Compile Include="Data\Migration\IDataMigrationGenerator.cs" />
<Compile Include="Data\Migration\DataMigration.cs" />
<Compile Include="Data\Migration\DataMigrationManager.cs" />
<Compile Include="Data\Migration\Records\DataMigrationRecord.cs" />