mirror of
https://github.com/OrchardCMS/Orchard.git
synced 2026-02-09 09:16:41 +08:00
Data migration fluent API
Inject a SchemaBuilder instance configured with DataTablePrefix in Data Migration classes inheriting from DataMigrationImpl --HG-- branch : dev
This commit is contained in:
@@ -0,0 +1,38 @@
|
|||||||
|
using System.Data;
|
||||||
|
using NUnit.Framework;
|
||||||
|
using Orchard.DataMigration.Schema;
|
||||||
|
|
||||||
|
namespace Orchard.Tests.DataMigration {
|
||||||
|
[TestFixture]
|
||||||
|
public class DataMigrationCommandsTests {
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void AllMethodsShouldBeCalledSuccessfully() {
|
||||||
|
var schemaBuilder = new SchemaBuilder("TEST_");
|
||||||
|
|
||||||
|
schemaBuilder
|
||||||
|
.CreateTable("User", table => table
|
||||||
|
.ContentPartRecord()
|
||||||
|
.Column("Id", DbType.Int32, column => column.PrimaryKey())
|
||||||
|
.Column("Firstname", DbType.String, column => column.Length(255))
|
||||||
|
.Column("Lastname", DbType.String, column => column.Precision(0).Scale(1))
|
||||||
|
.ForeignKey("User_Address", fk => fk.On("Id", "Address", "UserId")))
|
||||||
|
.CreateTable("Address", table => table
|
||||||
|
.VersionedContentPartRecord()
|
||||||
|
.Column("City", DbType.String)
|
||||||
|
.Column("ZIP", DbType.Int32, column => column.Unique())
|
||||||
|
.Column("UserId", DbType.Int32, column => column.NotNull()))
|
||||||
|
.AlterTable("User", table => table
|
||||||
|
.AddColumn("Age", DbType.Int32)
|
||||||
|
.AlterColumn("Lastname", column => column.Default("John"))
|
||||||
|
.AlterColumn("Lastname", column => column.Rename("John"))
|
||||||
|
.DropColumn("Lastname")
|
||||||
|
.CreateIndex("IDX_XYZ", "NickName")
|
||||||
|
.DropIndex("IDX_XYZ")
|
||||||
|
.AddForeignKey("FKL", fk => fk.On("Id", "A", "Id").On("Id", "B", "Id") )
|
||||||
|
.DropForeignKey("FKL"))
|
||||||
|
.DropTable("Address")
|
||||||
|
.ExecuteSql("DROP DATABASE", statement => statement.ForDialect("SQLite").ForDialect("MsSqlServer2008"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -2,10 +2,12 @@
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Autofac;
|
using Autofac;
|
||||||
|
using Moq;
|
||||||
using NHibernate;
|
using NHibernate;
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
using Orchard.ContentManagement.Records;
|
using Orchard.ContentManagement.Records;
|
||||||
using Orchard.Data;
|
using Orchard.Data;
|
||||||
|
using Orchard.Environment.Configuration;
|
||||||
using Orchard.Environment.Extensions;
|
using Orchard.Environment.Extensions;
|
||||||
using Orchard.Environment.Extensions.Folders;
|
using Orchard.Environment.Extensions.Folders;
|
||||||
using Orchard.Environment.Extensions.Loaders;
|
using Orchard.Environment.Extensions.Loaders;
|
||||||
@@ -42,6 +44,9 @@ namespace Orchard.Tests.DataMigration {
|
|||||||
|
|
||||||
var builder = new ContainerBuilder();
|
var builder = new ContainerBuilder();
|
||||||
_folders = new StubFolders();
|
_folders = new StubFolders();
|
||||||
|
|
||||||
|
builder.RegisterInstance(new ShellSettings { DataTablePrefix = "TEST_"});
|
||||||
|
|
||||||
builder.RegisterInstance(_folders).As<IExtensionFolders>();
|
builder.RegisterInstance(_folders).As<IExtensionFolders>();
|
||||||
builder.RegisterType<ExtensionManager>().As<IExtensionManager>();
|
builder.RegisterType<ExtensionManager>().As<IExtensionManager>();
|
||||||
builder.RegisterType<DataMigrationManager>().As<IDataMigrationManager>();
|
builder.RegisterType<DataMigrationManager>().As<IDataMigrationManager>();
|
||||||
@@ -149,6 +154,17 @@ namespace Orchard.Tests.DataMigration {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public class DataMigrationWithSchemaBuilder : DataMigrationImpl {
|
||||||
|
public override string Feature {
|
||||||
|
get { return "Feature1"; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public int Create() {
|
||||||
|
Assert.That(SchemaBuilder, Is.Not.Null);
|
||||||
|
Assert.That(SchemaBuilder.TablePrefix, Is.EqualTo("TEST_"));
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
[Test]
|
[Test]
|
||||||
public void DataMigrationShouldDoNothingIfNoDataMigrationIsProvidedForFeature() {
|
public void DataMigrationShouldDoNothingIfNoDataMigrationIsProvidedForFeature() {
|
||||||
Init(new Type[] {typeof (DataMigrationEmpty)});
|
Init(new Type[] {typeof (DataMigrationEmpty)});
|
||||||
@@ -162,7 +178,7 @@ features:
|
|||||||
Description: Feature
|
Description: Feature
|
||||||
");
|
");
|
||||||
|
|
||||||
_dataMigrationManager.Upgrade("Feature1");
|
_dataMigrationManager.Update("Feature1");
|
||||||
Assert.That(_repository.Table.Count(), Is.EqualTo(0));
|
Assert.That(_repository.Table.Count(), Is.EqualTo(0));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -179,7 +195,7 @@ features:
|
|||||||
Description: Feature
|
Description: Feature
|
||||||
");
|
");
|
||||||
|
|
||||||
_dataMigrationManager.Upgrade("Feature1");
|
_dataMigrationManager.Update("Feature1");
|
||||||
Assert.That(_repository.Table.Count(), Is.EqualTo(0));
|
Assert.That(_repository.Table.Count(), Is.EqualTo(0));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -196,7 +212,7 @@ features:
|
|||||||
Description: Feature
|
Description: Feature
|
||||||
");
|
");
|
||||||
|
|
||||||
_dataMigrationManager.Upgrade("Feature1");
|
_dataMigrationManager.Update("Feature1");
|
||||||
Assert.That(_repository.Table.Count(), Is.EqualTo(1));
|
Assert.That(_repository.Table.Count(), Is.EqualTo(1));
|
||||||
Assert.That(_repository.Table.First().Current, Is.EqualTo(999));
|
Assert.That(_repository.Table.First().Current, Is.EqualTo(999));
|
||||||
Assert.That(_repository.Table.First().DataMigrationClass, Is.EqualTo("Orchard.Tests.DataMigration.DataMigrationTests+DataMigration11Create"));
|
Assert.That(_repository.Table.First().DataMigrationClass, Is.EqualTo("Orchard.Tests.DataMigration.DataMigrationTests+DataMigration11Create"));
|
||||||
@@ -215,7 +231,7 @@ features:
|
|||||||
Description: Feature
|
Description: Feature
|
||||||
");
|
");
|
||||||
|
|
||||||
_dataMigrationManager.Upgrade("Feature1");
|
_dataMigrationManager.Update("Feature1");
|
||||||
Assert.That(_repository.Table.Count(), Is.EqualTo(1));
|
Assert.That(_repository.Table.Count(), Is.EqualTo(1));
|
||||||
Assert.That(_repository.Table.First().Current, Is.EqualTo(666));
|
Assert.That(_repository.Table.First().Current, Is.EqualTo(666));
|
||||||
}
|
}
|
||||||
@@ -237,7 +253,7 @@ features:
|
|||||||
DataMigrationClass = "Orchard.Tests.DataMigration.DataMigrationTests+DataMigrationSameMigrationClassCanEvolve"
|
DataMigrationClass = "Orchard.Tests.DataMigration.DataMigrationTests+DataMigrationSameMigrationClassCanEvolve"
|
||||||
});
|
});
|
||||||
|
|
||||||
_dataMigrationManager.Upgrade("Feature1");
|
_dataMigrationManager.Update("Feature1");
|
||||||
Assert.That(_repository.Table.Count(), Is.EqualTo(1));
|
Assert.That(_repository.Table.Count(), Is.EqualTo(1));
|
||||||
Assert.That(_repository.Table.First().Current, Is.EqualTo(999));
|
Assert.That(_repository.Table.First().Current, Is.EqualTo(999));
|
||||||
}
|
}
|
||||||
@@ -265,12 +281,28 @@ features:
|
|||||||
Feature2:
|
Feature2:
|
||||||
Description: Feature
|
Description: Feature
|
||||||
");
|
");
|
||||||
_dataMigrationManager.Upgrade("Feature1");
|
_dataMigrationManager.Update("Feature1");
|
||||||
Assert.That(_repository.Table.Count(), Is.EqualTo(2));
|
Assert.That(_repository.Table.Count(), Is.EqualTo(2));
|
||||||
Assert.That(_repository.Fetch(d => d.Current == 999).Count(), Is.EqualTo(2));
|
Assert.That(_repository.Fetch(d => d.Current == 999).Count(), Is.EqualTo(2));
|
||||||
Assert.That(_repository.Fetch(d => d.DataMigrationClass == "Orchard.Tests.DataMigration.DataMigrationTests+DataMigrationDependenciesModule1").Count(), Is.EqualTo(1));
|
Assert.That(_repository.Fetch(d => d.DataMigrationClass == "Orchard.Tests.DataMigration.DataMigrationTests+DataMigrationDependenciesModule1").Count(), Is.EqualTo(1));
|
||||||
Assert.That(_repository.Fetch(d => d.DataMigrationClass == "Orchard.Tests.DataMigration.DataMigrationTests+DataMigrationDependenciesModule2").Count(), Is.EqualTo(1));
|
Assert.That(_repository.Fetch(d => d.DataMigrationClass == "Orchard.Tests.DataMigration.DataMigrationTests+DataMigrationDependenciesModule2").Count(), Is.EqualTo(1));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void DataMigrationImplShouldGetASchemaBuilder() {
|
||||||
|
Init(new Type[] { typeof(DataMigrationWithSchemaBuilder) });
|
||||||
|
|
||||||
|
_folders.Manifests.Add("Module1", @"
|
||||||
|
name: Module1
|
||||||
|
version: 0.1
|
||||||
|
orchardversion: 1
|
||||||
|
features:
|
||||||
|
Feature1:
|
||||||
|
Description: Feature
|
||||||
|
");
|
||||||
|
|
||||||
|
_dataMigrationManager.Update("Feature1");
|
||||||
|
Assert.That(_repository.Table.Count(), Is.EqualTo(1));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -180,6 +180,7 @@
|
|||||||
<Compile Include="ContentManagement\Records\GammaRecord.cs">
|
<Compile Include="ContentManagement\Records\GammaRecord.cs">
|
||||||
<SubType>Code</SubType>
|
<SubType>Code</SubType>
|
||||||
</Compile>
|
</Compile>
|
||||||
|
<Compile Include="DataMigration\DataMigrationCommandsTests.cs" />
|
||||||
<Compile Include="DataMigration\DataMigrationTests.cs" />
|
<Compile Include="DataMigration\DataMigrationTests.cs" />
|
||||||
<Compile Include="DataUtility.cs" />
|
<Compile Include="DataUtility.cs" />
|
||||||
<Compile Include="Data\Builders\SessionFactoryBuilderTests.cs" />
|
<Compile Include="Data\Builders\SessionFactoryBuilderTests.cs" />
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ namespace Orchard.DataMigration.Commands {
|
|||||||
[OrchardSwitches("Feature")]
|
[OrchardSwitches("Feature")]
|
||||||
public string UpgradeDatabase() {
|
public string UpgradeDatabase() {
|
||||||
try {
|
try {
|
||||||
_dataMigrationManager.Upgrade(Feature);
|
_dataMigrationManager.Update(Feature);
|
||||||
}
|
}
|
||||||
catch ( Exception ex ) {
|
catch ( Exception ex ) {
|
||||||
Context.Output.WriteLine(T("An error occured while upgrading the database: " + ex.Message));
|
Context.Output.WriteLine(T("An error occured while upgrading the database: " + ex.Message));
|
||||||
|
|||||||
@@ -1,5 +1,11 @@
|
|||||||
namespace Orchard.DataMigration {
|
using Orchard.DataMigration.Schema;
|
||||||
public abstract class DataMigration : IDataMigration {
|
|
||||||
|
namespace Orchard.DataMigration {
|
||||||
|
/// <summary>
|
||||||
|
/// Data Migration classes can inherit from this class to get a SchemaBuilder instance configured with the current tenant database prefix
|
||||||
|
/// </summary>
|
||||||
|
public abstract class DataMigrationImpl : IDataMigration {
|
||||||
public abstract string Feature { get; }
|
public abstract string Feature { get; }
|
||||||
|
public SchemaBuilder SchemaBuilder { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
40
src/Orchard/DataMigration/DataMigrationCoordinator.cs
Normal file
40
src/Orchard/DataMigration/DataMigrationCoordinator.cs
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
using Orchard.Environment;
|
||||||
|
using Orchard.Environment.Extensions.Models;
|
||||||
|
|
||||||
|
namespace Orchard.DataMigration {
|
||||||
|
/// <summary>
|
||||||
|
/// Responsible for executing data migration tasks when a feature is enabled for the first time
|
||||||
|
/// 1) Initial install of a module:
|
||||||
|
/// Enable a feature for the first time => run data migration up to the latest version
|
||||||
|
/// Enable a feature on 2nd time => no data migration run
|
||||||
|
/// Disable a feature => no data migration
|
||||||
|
/// 2) Installing a newer version of a module
|
||||||
|
/// Don't do any data migration by default
|
||||||
|
/// 2 cases:
|
||||||
|
/// 1) feature wasn't not enabled when new code was installed
|
||||||
|
/// 2) feature was enabled when new code was installed
|
||||||
|
/// </summary>
|
||||||
|
public class DataMigrationCoordinator : IFeatureEventHandler {
|
||||||
|
private readonly IDataMigrationManager _dataMigrationManager;
|
||||||
|
|
||||||
|
public DataMigrationCoordinator(IDataMigrationManager dataMigrationManager) {
|
||||||
|
_dataMigrationManager = dataMigrationManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Install(Feature feature) {
|
||||||
|
var featureName = feature.Descriptor.Name;
|
||||||
|
if ( !_dataMigrationManager.IsFeatureAlreadyInstalled(featureName) ) {
|
||||||
|
_dataMigrationManager.Update(featureName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Enable(Feature feature) {
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Disable(Feature feature) {
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Uninstall(Feature feature) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -4,8 +4,10 @@ using System.Linq;
|
|||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using System.Text.RegularExpressions;
|
using System.Text.RegularExpressions;
|
||||||
using Orchard.Data;
|
using Orchard.Data;
|
||||||
|
using Orchard.DataMigration.Schema;
|
||||||
|
using Orchard.Environment.Configuration;
|
||||||
using Orchard.Environment.Extensions;
|
using Orchard.Environment.Extensions;
|
||||||
using Orchard.Environment.Extensions.Models;
|
using Orchard.Environment.State;
|
||||||
using Orchard.Logging;
|
using Orchard.Logging;
|
||||||
|
|
||||||
namespace Orchard.DataMigration {
|
namespace Orchard.DataMigration {
|
||||||
@@ -17,34 +19,46 @@ namespace Orchard.DataMigration {
|
|||||||
private readonly IRepository<DataMigrationRecord> _dataMigrationRepository;
|
private readonly IRepository<DataMigrationRecord> _dataMigrationRepository;
|
||||||
private readonly IDataMigrationGenerator _dataMigrationGenerator;
|
private readonly IDataMigrationGenerator _dataMigrationGenerator;
|
||||||
private readonly IExtensionManager _extensionManager;
|
private readonly IExtensionManager _extensionManager;
|
||||||
|
private readonly ShellSettings _shellSettings;
|
||||||
|
|
||||||
public DataMigrationManager(
|
public DataMigrationManager(
|
||||||
IEnumerable<IDataMigration> dataMigrations,
|
IEnumerable<IDataMigration> dataMigrations,
|
||||||
IRepository<DataMigrationRecord> dataMigrationRepository,
|
IRepository<DataMigrationRecord> dataMigrationRepository,
|
||||||
IDataMigrationGenerator dataMigrationGenerator,
|
IDataMigrationGenerator dataMigrationGenerator,
|
||||||
IExtensionManager extensionManager) {
|
IExtensionManager extensionManager,
|
||||||
|
ShellSettings shellSettings) {
|
||||||
_dataMigrations = dataMigrations;
|
_dataMigrations = dataMigrations;
|
||||||
_dataMigrationRepository = dataMigrationRepository;
|
_dataMigrationRepository = dataMigrationRepository;
|
||||||
_dataMigrationGenerator = dataMigrationGenerator;
|
_dataMigrationGenerator = dataMigrationGenerator;
|
||||||
_extensionManager = extensionManager;
|
_extensionManager = extensionManager;
|
||||||
|
_shellSettings = shellSettings;
|
||||||
Logger = NullLogger.Instance;
|
Logger = NullLogger.Instance;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ILogger Logger { get; set; }
|
public ILogger Logger { get; set; }
|
||||||
|
|
||||||
public void Upgrade(string feature) {
|
public IEnumerable<string> GetFeaturesThatNeedUpdate() {
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Update(IEnumerable<string> features) {
|
||||||
|
foreach(var feature in features) {
|
||||||
|
Update(feature);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Update(string feature){
|
||||||
|
|
||||||
// proceed with dependent features first, whatever the module it's in
|
// proceed with dependent features first, whatever the module it's in
|
||||||
var dependencies = _extensionManager
|
var dependencies = ShellStateCoordinator.OrderByDependencies(_extensionManager.AvailableExtensions()
|
||||||
.AvailableExtensions()
|
.SelectMany(ext => ext.Features))
|
||||||
.SelectMany(e => e.Features)
|
|
||||||
.Where(f => String.Equals(f.Name, feature, StringComparison.OrdinalIgnoreCase))
|
.Where(f => String.Equals(f.Name, feature, StringComparison.OrdinalIgnoreCase))
|
||||||
.Where(f => f.Dependencies != null)
|
.Where(f => f.Dependencies != null)
|
||||||
.SelectMany( f => f.Dependencies )
|
.SelectMany( f => f.Dependencies )
|
||||||
.ToList();
|
.ToList();
|
||||||
|
|
||||||
foreach(var dependency in dependencies) {
|
foreach(var dependency in dependencies) {
|
||||||
Upgrade(dependency);
|
Update(dependency);
|
||||||
}
|
}
|
||||||
|
|
||||||
var migrations = GetDataMigrations(feature);
|
var migrations = GetDataMigrations(feature);
|
||||||
@@ -55,9 +69,7 @@ namespace Orchard.DataMigration {
|
|||||||
var tempMigration = migration;
|
var tempMigration = migration;
|
||||||
|
|
||||||
// get current version for this migration
|
// get current version for this migration
|
||||||
var dataMigrationRecord = _dataMigrationRepository.Table
|
var dataMigrationRecord = GetDataMigrationRecord(tempMigration);
|
||||||
.Where(dm => dm.DataMigrationClass == tempMigration.GetType().FullName)
|
|
||||||
.FirstOrDefault();
|
|
||||||
|
|
||||||
var updateMethodNameRegex = new Regex(@"^UpdateFrom(?<version>\d+)$", RegexOptions.Compiled);
|
var updateMethodNameRegex = new Regex(@"^UpdateFrom(?<version>\d+)$", RegexOptions.Compiled);
|
||||||
var current = 0;
|
var current = 0;
|
||||||
@@ -81,6 +93,7 @@ namespace Orchard.DataMigration {
|
|||||||
|
|
||||||
// update methods might also be called after Create()
|
// update methods might also be called after Create()
|
||||||
var lookupTable = new Dictionary<int, MethodInfo>();
|
var lookupTable = new Dictionary<int, MethodInfo>();
|
||||||
|
|
||||||
// construct a lookup table with all managed initial versions
|
// construct a lookup table with all managed initial versions
|
||||||
foreach(var methodInfo in migration.GetType().GetMethods(BindingFlags.Public | BindingFlags.Instance)) {
|
foreach(var methodInfo in migration.GetType().GetMethods(BindingFlags.Public | BindingFlags.Instance)) {
|
||||||
var match = updateMethodNameRegex.Match(methodInfo.Name);
|
var match = updateMethodNameRegex.Match(methodInfo.Name);
|
||||||
@@ -96,29 +109,50 @@ namespace Orchard.DataMigration {
|
|||||||
}
|
}
|
||||||
catch (Exception ex) {
|
catch (Exception ex) {
|
||||||
Logger.Error(ex, "An unexpected error orccured while applying migration on {0} from version {1}", feature, current);
|
Logger.Error(ex, "An unexpected error orccured while applying migration on {0} from version {1}", feature, current);
|
||||||
|
throw;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// if current is 0, it means no upgrade/create method was found or succeeded
|
// if current is 0, it means no upgrade/create method was found or succeeded
|
||||||
if ( current != 0 ) {
|
if (current == 0) {
|
||||||
if (dataMigrationRecord == null) {
|
continue;
|
||||||
_dataMigrationRepository.Create(new DataMigrationRecord {Current = current, DataMigrationClass = migration.GetType().FullName});
|
}
|
||||||
}
|
if (dataMigrationRecord == null) {
|
||||||
else {
|
_dataMigrationRepository.Create(new DataMigrationRecord {Current = current, DataMigrationClass = migration.GetType().FullName});
|
||||||
dataMigrationRecord.Current = current;
|
}
|
||||||
_dataMigrationRepository.Update(dataMigrationRecord);
|
else {
|
||||||
}
|
dataMigrationRecord.Current = current;
|
||||||
|
_dataMigrationRepository.Update(dataMigrationRecord);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private DataMigrationRecord GetDataMigrationRecord(IDataMigration tempMigration) {
|
||||||
|
return _dataMigrationRepository.Table
|
||||||
|
.Where(dm => dm.DataMigrationClass == tempMigration.GetType().FullName)
|
||||||
|
.FirstOrDefault();
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Returns all the available IDataMigration instances for a specific module
|
/// Returns all the available IDataMigration instances for a specific module, and inject necessary builders
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public IEnumerable<IDataMigration> GetDataMigrations(string feature) {
|
private IEnumerable<IDataMigration> GetDataMigrations(string feature) {
|
||||||
return _dataMigrations
|
var migrations = _dataMigrations
|
||||||
.Where(dm => String.Equals(dm.Feature, feature, StringComparison.OrdinalIgnoreCase))
|
.Where(dm => String.Equals(dm.Feature, feature, StringComparison.OrdinalIgnoreCase))
|
||||||
.ToList();
|
.ToList();
|
||||||
|
|
||||||
|
foreach (var migration in migrations.OfType<DataMigrationImpl>()) {
|
||||||
|
migration.SchemaBuilder = new SchemaBuilder(_shellSettings.DataTablePrefix);
|
||||||
|
}
|
||||||
|
|
||||||
|
return migrations;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Whether a feature has already been installed, i.e. one of its Data Migration class has already been processed
|
||||||
|
/// </summary>
|
||||||
|
public bool IsFeatureAlreadyInstalled(string feature) {
|
||||||
|
return GetDataMigrations(feature).Any(dataMigration => GetDataMigrationRecord(dataMigration) != null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,25 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
namespace Orchard.DataMigration {
|
namespace Orchard.DataMigration {
|
||||||
public interface IDataMigrationManager : IDependency {
|
public interface IDataMigrationManager : IDependency {
|
||||||
void Upgrade(string feature);
|
/// <summary>
|
||||||
|
/// Whether a feature has already been installed, i.e. one of its Data Migration class has already been processed
|
||||||
|
/// </summary>
|
||||||
|
bool IsFeatureAlreadyInstalled(string feature);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns the features which have at least one Data Migration class with a corresponding Upgrade method to be called
|
||||||
|
/// </summary>
|
||||||
|
IEnumerable<string> GetFeaturesThatNeedUpdate();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Updates the database to the latest version for the specified feature
|
||||||
|
/// </summary>
|
||||||
|
void Update(string feature);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Updates the database to the latest version for the specified features
|
||||||
|
/// </summary>
|
||||||
|
void Update(IEnumerable<string> features);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
15
src/Orchard/DataMigration/Schema/AlterColumnCommand.cs
Normal file
15
src/Orchard/DataMigration/Schema/AlterColumnCommand.cs
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
namespace Orchard.DataMigration.Schema {
|
||||||
|
public class AlterColumnCommand : ColumnCommand {
|
||||||
|
private string _newName;
|
||||||
|
|
||||||
|
public AlterColumnCommand(string name)
|
||||||
|
: base(name) {
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public AlterColumnCommand Rename(string name) {
|
||||||
|
_newName = name;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
64
src/Orchard/DataMigration/Schema/AlterTableCommand.cs
Normal file
64
src/Orchard/DataMigration/Schema/AlterTableCommand.cs
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
using System;
|
||||||
|
using System.Data;
|
||||||
|
|
||||||
|
namespace Orchard.DataMigration.Schema {
|
||||||
|
public class AlterTableCommand : SchemaCommand {
|
||||||
|
public AlterTableCommand(string name)
|
||||||
|
: base(name) {
|
||||||
|
}
|
||||||
|
|
||||||
|
public AlterTableCommand AddColumn(string name, DbType dbType, Action<CreateColumnCommand> column = null) {
|
||||||
|
var command = new CreateColumnCommand(name);
|
||||||
|
command.Type(dbType);
|
||||||
|
|
||||||
|
if(column != null) {
|
||||||
|
column(command);
|
||||||
|
}
|
||||||
|
|
||||||
|
_tableCommands.Add(command);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public AlterTableCommand DropColumn(string name) {
|
||||||
|
var command = new DropColumnCommand(name);
|
||||||
|
_tableCommands.Add(command);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public AlterTableCommand AlterColumn(string name, Action<AlterColumnCommand> column = null) {
|
||||||
|
var command = new AlterColumnCommand(name);
|
||||||
|
|
||||||
|
if ( column != null ) {
|
||||||
|
column(command);
|
||||||
|
}
|
||||||
|
|
||||||
|
_tableCommands.Add(command);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public AlterTableCommand CreateIndex(string name, params string[] columnNames) {
|
||||||
|
var command = new CreateIndexCommand(name, columnNames);
|
||||||
|
_tableCommands.Add(command);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public AlterTableCommand DropIndex(string name) {
|
||||||
|
var command = new DropIndexCommand(name);
|
||||||
|
_tableCommands.Add(command);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public AlterTableCommand AddForeignKey(string name, Action<CreateForeignKeyCommand> fk) {
|
||||||
|
var command = new CreateForeignKeyCommand(name);
|
||||||
|
fk(command);
|
||||||
|
_tableCommands.Add(command);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public AlterTableCommand DropForeignKey(string name) {
|
||||||
|
var command = new DropForeignKeyCommand(name);
|
||||||
|
_tableCommands.Add(command);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
23
src/Orchard/DataMigration/Schema/ColumnCommand.cs
Normal file
23
src/Orchard/DataMigration/Schema/ColumnCommand.cs
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
using System.Data;
|
||||||
|
|
||||||
|
namespace Orchard.DataMigration.Schema {
|
||||||
|
public class ColumnCommand : TableCommand {
|
||||||
|
private DbType _dbType;
|
||||||
|
private object _default;
|
||||||
|
public ColumnCommand(string name) : base(name) {
|
||||||
|
_dbType = DbType.Object;
|
||||||
|
_default = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ColumnCommand Type(DbType dbType) {
|
||||||
|
_dbType = dbType;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ColumnCommand Default(object @default) {
|
||||||
|
_default = @default;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
60
src/Orchard/DataMigration/Schema/CreateColumnCommand.cs
Normal file
60
src/Orchard/DataMigration/Schema/CreateColumnCommand.cs
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
namespace Orchard.DataMigration.Schema {
|
||||||
|
public class CreateColumnCommand : ColumnCommand {
|
||||||
|
private bool _primaryKey;
|
||||||
|
private byte? _precision;
|
||||||
|
private byte? _scale;
|
||||||
|
private int? _length;
|
||||||
|
private bool _notNull;
|
||||||
|
private bool _unique;
|
||||||
|
|
||||||
|
|
||||||
|
public CreateColumnCommand(string name) : base(name) {
|
||||||
|
_precision = null;
|
||||||
|
_scale = null;
|
||||||
|
_length = null;
|
||||||
|
_notNull = false;
|
||||||
|
_unique = false;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public CreateColumnCommand PrimaryKey() {
|
||||||
|
_primaryKey = true;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public CreateColumnCommand Precision(byte? precision) {
|
||||||
|
_precision = precision;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public CreateColumnCommand Scale(byte? scale) {
|
||||||
|
_scale = scale;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public CreateColumnCommand Length(int? length) {
|
||||||
|
_length = length;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public CreateColumnCommand NotNull() {
|
||||||
|
_notNull = true;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public CreateColumnCommand Nullable() {
|
||||||
|
_notNull = false;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public CreateColumnCommand Unique() {
|
||||||
|
_unique = true;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public CreateColumnCommand NotUnique() {
|
||||||
|
_unique = false;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
31
src/Orchard/DataMigration/Schema/CreateForeignKeyCommand.cs
Normal file
31
src/Orchard/DataMigration/Schema/CreateForeignKeyCommand.cs
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace Orchard.DataMigration.Schema {
|
||||||
|
public class CreateForeignKeyCommand : TableCommand {
|
||||||
|
protected readonly List<ForeignKeyClause> _foreignKeyClauses;
|
||||||
|
|
||||||
|
public CreateForeignKeyCommand(string name)
|
||||||
|
: base(name) {
|
||||||
|
_foreignKeyClauses = new List<ForeignKeyClause>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public CreateForeignKeyCommand On(string srcColumn, string destTable, string destColumn) {
|
||||||
|
_foreignKeyClauses.Add(new ForeignKeyClause(srcColumn, destTable, destColumn));
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class ForeignKeyClause {
|
||||||
|
public ForeignKeyClause(string srcColumn, string destTable, string destColumn) {
|
||||||
|
SrcColumn = srcColumn;
|
||||||
|
DestTable = destTable;
|
||||||
|
DestColumn = destColumn;
|
||||||
|
}
|
||||||
|
|
||||||
|
public string DestColumn { get; private set; }
|
||||||
|
|
||||||
|
public string DestTable { get; private set; }
|
||||||
|
|
||||||
|
public string SrcColumn { get; private set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
10
src/Orchard/DataMigration/Schema/CreateIndexCommand.cs
Normal file
10
src/Orchard/DataMigration/Schema/CreateIndexCommand.cs
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
namespace Orchard.DataMigration.Schema {
|
||||||
|
public class CreateIndexCommand : TableCommand {
|
||||||
|
public CreateIndexCommand(string name, params string[] columnNames)
|
||||||
|
: base(name) {
|
||||||
|
ColumnNames = columnNames;
|
||||||
|
}
|
||||||
|
|
||||||
|
public string[] ColumnNames { get; private set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
38
src/Orchard/DataMigration/Schema/CreateTableCommand.cs
Normal file
38
src/Orchard/DataMigration/Schema/CreateTableCommand.cs
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
using System;
|
||||||
|
using System.Data;
|
||||||
|
|
||||||
|
namespace Orchard.DataMigration.Schema {
|
||||||
|
public class CreateTableCommand : SchemaCommand {
|
||||||
|
public CreateTableCommand(string name)
|
||||||
|
: base(name) {
|
||||||
|
}
|
||||||
|
|
||||||
|
public CreateTableCommand Column(string name, DbType dbType, Action<CreateColumnCommand> column = null) {
|
||||||
|
var command = new CreateColumnCommand(name);
|
||||||
|
command.Type(dbType);
|
||||||
|
|
||||||
|
if ( column != null ) {
|
||||||
|
column(command);
|
||||||
|
}
|
||||||
|
_tableCommands.Add(command);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public CreateTableCommand ContentPartRecord() {
|
||||||
|
/// TODO: Call Column() with necessary information for content part records
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public CreateTableCommand VersionedContentPartRecord() {
|
||||||
|
/// TODO: Call Column() with necessary information for content part records
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public CreateTableCommand ForeignKey(string name, Action<CreateForeignKeyCommand> fk) {
|
||||||
|
var command = new CreateForeignKeyCommand(name);
|
||||||
|
fk(command);
|
||||||
|
_tableCommands.Add(command);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
8
src/Orchard/DataMigration/Schema/DropColumnCommand.cs
Normal file
8
src/Orchard/DataMigration/Schema/DropColumnCommand.cs
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
namespace Orchard.DataMigration.Schema {
|
||||||
|
public class DropColumnCommand : ColumnCommand {
|
||||||
|
public DropColumnCommand(string name)
|
||||||
|
: base(name) {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
namespace Orchard.DataMigration.Schema {
|
||||||
|
public class DropForeignKeyCommand : TableCommand {
|
||||||
|
|
||||||
|
public DropForeignKeyCommand(string name)
|
||||||
|
: base(name) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
8
src/Orchard/DataMigration/Schema/DropIndexCommand.cs
Normal file
8
src/Orchard/DataMigration/Schema/DropIndexCommand.cs
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
namespace Orchard.DataMigration.Schema {
|
||||||
|
public class DropIndexCommand : TableCommand {
|
||||||
|
|
||||||
|
public DropIndexCommand(string name)
|
||||||
|
: base(name) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
7
src/Orchard/DataMigration/Schema/DropTableCommand.cs
Normal file
7
src/Orchard/DataMigration/Schema/DropTableCommand.cs
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
namespace Orchard.DataMigration.Schema {
|
||||||
|
public class DropTableCommand : SchemaCommand {
|
||||||
|
public DropTableCommand(string name)
|
||||||
|
: base(name) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
46
src/Orchard/DataMigration/Schema/SchemaBuilder.cs
Normal file
46
src/Orchard/DataMigration/Schema/SchemaBuilder.cs
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace Orchard.DataMigration.Schema {
|
||||||
|
public class SchemaBuilder {
|
||||||
|
|
||||||
|
private readonly List<SchemaCommand> _schemaCommands;
|
||||||
|
|
||||||
|
public SchemaBuilder() {
|
||||||
|
_schemaCommands = new List<SchemaCommand>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public SchemaBuilder(string tablePrefix) : this() {
|
||||||
|
TablePrefix = tablePrefix;
|
||||||
|
}
|
||||||
|
|
||||||
|
public string TablePrefix { get; private set; }
|
||||||
|
|
||||||
|
public SchemaBuilder CreateTable(string name, Action<CreateTableCommand> table) {
|
||||||
|
var createTable = new CreateTableCommand(name);
|
||||||
|
table(createTable);
|
||||||
|
_schemaCommands.Add(createTable);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public SchemaBuilder AlterTable(string name, Action<AlterTableCommand> table) {
|
||||||
|
var alterTable = new AlterTableCommand(name);
|
||||||
|
table(alterTable);
|
||||||
|
_schemaCommands.Add(alterTable);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public SchemaBuilder DropTable(string name) {
|
||||||
|
var deleteTable = new DropTableCommand(name);
|
||||||
|
_schemaCommands.Add(deleteTable);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public SchemaBuilder ExecuteSql(string sql, Action<SqlStatementCommand> statement) {
|
||||||
|
var sqlStatmentCommand = new SqlStatementCommand(sql);
|
||||||
|
statement(sqlStatmentCommand);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
19
src/Orchard/DataMigration/Schema/SchemaCommand.cs
Normal file
19
src/Orchard/DataMigration/Schema/SchemaCommand.cs
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace Orchard.DataMigration.Schema {
|
||||||
|
public class SchemaCommand {
|
||||||
|
protected readonly List<TableCommand> _tableCommands;
|
||||||
|
|
||||||
|
public SchemaCommand(string tableName) {
|
||||||
|
_tableCommands = new List<TableCommand>();
|
||||||
|
Name(tableName);
|
||||||
|
}
|
||||||
|
|
||||||
|
public string TableName { get; private set; }
|
||||||
|
|
||||||
|
public SchemaCommand Name(string name) {
|
||||||
|
TableName = name;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
19
src/Orchard/DataMigration/Schema/SqlStatementCommand.cs
Normal file
19
src/Orchard/DataMigration/Schema/SqlStatementCommand.cs
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace Orchard.DataMigration.Schema {
|
||||||
|
public class SqlStatementCommand : SchemaCommand {
|
||||||
|
protected readonly List<string> _dialects;
|
||||||
|
public SqlStatementCommand(string sql)
|
||||||
|
: base("") {
|
||||||
|
Sql = sql;
|
||||||
|
_dialects = new List<string>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public string Sql { get; private set; }
|
||||||
|
|
||||||
|
public SqlStatementCommand ForDialect(string dialect) {
|
||||||
|
_dialects.Add(dialect);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
10
src/Orchard/DataMigration/Schema/TableCommand.cs
Normal file
10
src/Orchard/DataMigration/Schema/TableCommand.cs
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
namespace Orchard.DataMigration.Schema {
|
||||||
|
public class TableCommand {
|
||||||
|
private string _name;
|
||||||
|
|
||||||
|
public TableCommand(string name) {
|
||||||
|
_name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -195,7 +195,7 @@ namespace Orchard.Environment.State {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static IEnumerable<FeatureDescriptor> OrderByDependencies(IEnumerable<FeatureDescriptor> descriptors) {
|
public static IEnumerable<FeatureDescriptor> OrderByDependencies(IEnumerable<FeatureDescriptor> descriptors) {
|
||||||
var population = descriptors.Select(d => new Linkage {
|
var population = descriptors.Select(d => new Linkage {
|
||||||
Feature = d
|
Feature = d
|
||||||
}).ToArray();
|
}).ToArray();
|
||||||
|
|||||||
@@ -349,7 +349,19 @@
|
|||||||
<Compile Include="ContentManagement\ViewModels\TemplateViewModel.cs">
|
<Compile Include="ContentManagement\ViewModels\TemplateViewModel.cs">
|
||||||
<SubType>Code</SubType>
|
<SubType>Code</SubType>
|
||||||
</Compile>
|
</Compile>
|
||||||
|
<Compile Include="DataMigration\Schema\SqlStatementCommand.cs" />
|
||||||
|
<Compile Include="DataMigration\Schema\CreateColumnCommand.cs" />
|
||||||
|
<Compile Include="DataMigration\Schema\CreateForeignKeyCommand.cs" />
|
||||||
|
<Compile Include="DataMigration\Schema\DropForeignKeyCommand.cs" />
|
||||||
|
<Compile Include="DataMigration\Schema\DropIndexCommand.cs" />
|
||||||
|
<Compile Include="DataMigration\Schema\CreateIndexCommand.cs" />
|
||||||
|
<Compile Include="DataMigration\Schema\DropColumnCommand.cs" />
|
||||||
|
<Compile Include="DataMigration\Schema\AlterColumnCommand.cs" />
|
||||||
|
<Compile Include="DataMigration\Schema\DropTableCommand.cs" />
|
||||||
|
<Compile Include="DataMigration\Schema\AlterTableCommand.cs" />
|
||||||
<Compile Include="DataMigration\Commands\DataMigrationCommands.cs" />
|
<Compile Include="DataMigration\Commands\DataMigrationCommands.cs" />
|
||||||
|
<Compile Include="DataMigration\Schema\SchemaBuilder.cs" />
|
||||||
|
<Compile Include="DataMigration\DataMigrationCoordinator.cs" />
|
||||||
<Compile Include="DataMigration\IDataMigrationCommand.cs" />
|
<Compile Include="DataMigration\IDataMigrationCommand.cs" />
|
||||||
<Compile Include="DataMigration\DefaultDataMigrationGenerator.cs" />
|
<Compile Include="DataMigration\DefaultDataMigrationGenerator.cs" />
|
||||||
<Compile Include="DataMigration\IDataMigrationGenerator.cs" />
|
<Compile Include="DataMigration\IDataMigrationGenerator.cs" />
|
||||||
@@ -358,6 +370,10 @@
|
|||||||
<Compile Include="DataMigration\DataMigrationRecord.cs" />
|
<Compile Include="DataMigration\DataMigrationRecord.cs" />
|
||||||
<Compile Include="DataMigration\IDataMigration.cs" />
|
<Compile Include="DataMigration\IDataMigration.cs" />
|
||||||
<Compile Include="DataMigration\IDataMigrationManager.cs" />
|
<Compile Include="DataMigration\IDataMigrationManager.cs" />
|
||||||
|
<Compile Include="DataMigration\Schema\ColumnCommand.cs" />
|
||||||
|
<Compile Include="DataMigration\Schema\CreateTableCommand.cs" />
|
||||||
|
<Compile Include="DataMigration\Schema\TableCommand.cs" />
|
||||||
|
<Compile Include="DataMigration\Schema\SchemaCommand.cs" />
|
||||||
<Compile Include="Data\SessionLocator.cs" />
|
<Compile Include="Data\SessionLocator.cs" />
|
||||||
<Compile Include="Data\IRepository.cs" />
|
<Compile Include="Data\IRepository.cs" />
|
||||||
<Compile Include="Data\ISessionLocator.cs" />
|
<Compile Include="Data\ISessionLocator.cs" />
|
||||||
|
|||||||
Reference in New Issue
Block a user