mirror of
https://github.com/OrchardCMS/Orchard.git
synced 2025-08-01 19:06:11 +08:00
Better data migration scaffolding and some unit tests for it
--HG-- branch : dev
This commit is contained in:
parent
4fb3c51dff
commit
6ba6892e39
194
src/Orchard.Tests/DataMigration/SchemaCommandGeneratorTests.cs
Normal file
194
src/Orchard.Tests/DataMigration/SchemaCommandGeneratorTests.cs
Normal file
@ -0,0 +1,194 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.Data;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using Autofac;
|
||||
using Autofac.Features.Metadata;
|
||||
using NHibernate;
|
||||
using NUnit.Framework;
|
||||
using Orchard.ContentManagement.Records;
|
||||
using Orchard.Data;
|
||||
using Orchard.Data.Conventions;
|
||||
using Orchard.Data.Migration;
|
||||
using Orchard.Data.Migration.Generator;
|
||||
using Orchard.Data.Migration.Interpreters;
|
||||
using Orchard.Data.Migration.Records;
|
||||
using Orchard.Data.Migration.Schema;
|
||||
using Orchard.DevTools.Services;
|
||||
using Orchard.Environment.Configuration;
|
||||
using Orchard.Environment.Extensions;
|
||||
using Orchard.Environment.Extensions.Folders;
|
||||
using Orchard.Environment.Extensions.Models;
|
||||
using Orchard.Environment.ShellBuilders.Models;
|
||||
using Orchard.FileSystems.AppData;
|
||||
using Orchard.Tests.ContentManagement;
|
||||
using Orchard.Data.Providers;
|
||||
using Orchard.Tests.FileSystems.AppData;
|
||||
|
||||
namespace Orchard.Tests.DataMigration {
|
||||
[TestFixture]
|
||||
public class SchemaCommandGeneratorTests {
|
||||
private IContainer _container;
|
||||
private StubFolders _folders;
|
||||
private ISchemaCommandGenerator _generator;
|
||||
|
||||
private ISessionFactory _sessionFactory;
|
||||
private ISession _session;
|
||||
|
||||
[TestFixtureSetUp]
|
||||
public void CreateDb() {
|
||||
var types = new[] {
|
||||
typeof(BlogRecord),
|
||||
typeof(BodyRecord),
|
||||
typeof(BlogArchiveRecord),
|
||||
typeof(ContentItemVersionRecord),
|
||||
typeof(ContentItemRecord),
|
||||
typeof(ContentTypeRecord)};
|
||||
|
||||
var databaseFileName = System.IO.Path.GetTempFileName();
|
||||
_sessionFactory = DataUtility.CreateSessionFactory(
|
||||
databaseFileName, types );
|
||||
|
||||
var builder = new ContainerBuilder();
|
||||
_folders = new StubFolders();
|
||||
|
||||
var manager = (IDataServicesProviderFactory)new DataServicesProviderFactory(new[] {
|
||||
new Meta<CreateDataServicesProvider>(
|
||||
(dataFolder, connectionString) => new SqlCeDataServicesProvider(dataFolder, connectionString),
|
||||
new Dictionary<string, object> {{"ProviderName", "SqlCe"}})
|
||||
});
|
||||
|
||||
builder.RegisterInstance(new ShellSettings { Name = "Default", DataTablePrefix = "TEST_", DataProvider = "SqlCe"});
|
||||
builder.RegisterInstance(AppDataFolderTests.CreateAppDataFolder(Path.GetDirectoryName(databaseFileName))).As<IAppDataFolder>();
|
||||
builder.RegisterType<SessionConfigurationCache>().As<ISessionConfigurationCache>();
|
||||
builder.RegisterType<SqlCeDataServicesProvider>().As<IDataServicesProvider>();
|
||||
builder.RegisterInstance(manager).As<IDataServicesProviderFactory>();
|
||||
builder.RegisterType<NullInterpreter>().As<IDataMigrationInterpreter>();
|
||||
builder.RegisterType<SessionFactoryHolder>().As<ISessionFactoryHolder>();
|
||||
builder.RegisterInstance(_folders).As<IExtensionFolders>();
|
||||
builder.RegisterType<SchemaCommandGenerator>().As<ISchemaCommandGenerator>();
|
||||
builder.RegisterGeneric(typeof(Repository<>)).As(typeof(IRepository<>));
|
||||
_session = _sessionFactory.OpenSession();
|
||||
builder.RegisterInstance(new DefaultContentManagerTests.TestSessionLocator(_session)).As<ISessionLocator>();
|
||||
|
||||
builder.RegisterInstance(new ShellBlueprint() { Records = types.Select(t => new RecordBlueprint { Feature = new Feature() { Descriptor = new FeatureDescriptor() { Name = "Feature1" } }, TableName = "TEST_" + t.Name, Type = t })});
|
||||
|
||||
_container = builder.Build();
|
||||
_generator = _container.Resolve<ISchemaCommandGenerator>();
|
||||
|
||||
_folders.Manifests.Add("Module1", @"
|
||||
name: Module1
|
||||
version: 0.1
|
||||
orchardversion: 1
|
||||
features:
|
||||
Feature1:
|
||||
Description: Feature
|
||||
");
|
||||
}
|
||||
|
||||
public class StubFolders : IExtensionFolders {
|
||||
public StubFolders() {
|
||||
Manifests = new Dictionary<string, string>();
|
||||
}
|
||||
|
||||
public IDictionary<string, string> Manifests { get; set; }
|
||||
|
||||
public IEnumerable<ExtensionDescriptor> AvailableExtensions() {
|
||||
foreach (var e in Manifests) {
|
||||
string name = e.Key;
|
||||
var parseResult = ExtensionFolders.ParseManifest(Manifests[name]);
|
||||
yield return ExtensionFolders.GetDescriptorForExtension("~/", name, "Module", parseResult);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
[Test]
|
||||
public void ShouldCreateCreateTableCommands() {
|
||||
var commands = _generator.GetCreateFeatureCommands("Feature1", false).ToList();
|
||||
Assert.That(commands, Is.Not.Null);
|
||||
Assert.That(commands.Count(), Is.EqualTo(6));
|
||||
|
||||
var blogRecord = commands.Where(c => c.Name == "TEST_BlogRecord").First();
|
||||
|
||||
Assert.That(blogRecord.TableCommands.OfType<CreateColumnCommand>().Any(c => c.ColumnName == "Id" && !c.IsIdentity && c.IsPrimaryKey && c.DbType == DbType.Int32));
|
||||
Assert.That(blogRecord.TableCommands.OfType<CreateColumnCommand>().Any(c => c.ColumnName == "Description" && c.DbType == DbType.String));
|
||||
Assert.That(blogRecord.TableCommands.OfType<CreateColumnCommand>().Any(c => c.ColumnName == "PostCount" && c.DbType == DbType.Int32));
|
||||
|
||||
var blogArchiveRecord = commands.Where(c => c.Name == "TEST_BlogArchiveRecord").First();
|
||||
Assert.That(blogArchiveRecord.TableCommands.OfType<CreateColumnCommand>().Any(c => c.ColumnName == "Id" && c.IsPrimaryKey && c.DbType == DbType.Int32));
|
||||
Assert.That(blogArchiveRecord.TableCommands.OfType<CreateColumnCommand>().Any(c => c.ColumnName == "Year" && c.DbType == DbType.Int32));
|
||||
Assert.That(blogArchiveRecord.TableCommands.OfType<CreateColumnCommand>().Any(c => c.ColumnName == "Month" && c.DbType == DbType.Int32));
|
||||
Assert.That(blogArchiveRecord.TableCommands.OfType<CreateColumnCommand>().Any(c => c.ColumnName == "PostCount" && c.DbType == DbType.Int32));
|
||||
Assert.That(blogArchiveRecord.TableCommands.OfType<CreateColumnCommand>().Any(c => c.ColumnName == "Blog_id" && c.DbType == DbType.Int32));
|
||||
|
||||
var bodyRecord = commands.Where(c => c.Name == "TEST_BodyRecord").First();
|
||||
Assert.That(bodyRecord.TableCommands.OfType<CreateColumnCommand>().Any(c => c.ColumnName == "Id" && c.IsPrimaryKey && c.DbType == DbType.Int32));
|
||||
Assert.That(bodyRecord.TableCommands.OfType<CreateColumnCommand>().Any(c => c.ColumnName == "Text" && c.DbType == DbType.String && c.Length == 10000));
|
||||
Assert.That(bodyRecord.TableCommands.OfType<CreateColumnCommand>().Any(c => c.ColumnName == "Format" && c.DbType == DbType.String && c.Length == 42));
|
||||
Assert.That(bodyRecord.TableCommands.OfType<CreateColumnCommand>().Any(c => c.ColumnName == "ContentItemRecord_id" && c.DbType == DbType.Int32));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ScaffoldingCommandInterpreterShouldDetectContentParts() {
|
||||
|
||||
var commands = _generator.GetCreateFeatureCommands("Feature1", false).ToList();
|
||||
Assert.That(commands, Is.Not.Null);
|
||||
Assert.That(commands.Count(), Is.EqualTo(6));
|
||||
|
||||
var sw = new StringWriter();
|
||||
var interpreter = new ScaffoldingCommandInterpreter(sw);
|
||||
|
||||
var blogRecord = commands.Where(c => c.Name == "TEST_BlogRecord").First();
|
||||
var blogArchiveRecord = commands.Where(c => c.Name == "TEST_BlogArchiveRecord").First();
|
||||
var bodyRecord = commands.Where(c => c.Name == "TEST_BodyRecord").First();
|
||||
|
||||
sw.GetStringBuilder().Clear();
|
||||
interpreter.Visit(blogRecord);
|
||||
Assert.That(sw.ToString().Contains("SchemaBuilder.CreateTable(\"TEST_BlogRecord"));
|
||||
Assert.That(sw.ToString().Contains(".ContentPartRecord()"));
|
||||
Assert.That(sw.ToString().Contains(".Column(\"Description\", DbType.String)"));
|
||||
Assert.That(sw.ToString().Contains(".Column(\"PostCount\", DbType.Int32)"));
|
||||
|
||||
sw.GetStringBuilder().Clear();
|
||||
interpreter.Visit(blogArchiveRecord);
|
||||
Assert.That(sw.ToString().Contains("SchemaBuilder.CreateTable(\"TEST_BlogArchiveRecord"));
|
||||
Assert.That(sw.ToString().Contains(".Column(\"Id\", DbType.Int32, column => column.PrimaryKey().Identity())"));
|
||||
Assert.That(sw.ToString().Contains(".Column(\"Year\", DbType.Int32)"));
|
||||
Assert.That(sw.ToString().Contains(".Column(\"Month\", DbType.Int32)"));
|
||||
Assert.That(sw.ToString().Contains(".Column(\"PostCount\", DbType.Int32)"));
|
||||
Assert.That(sw.ToString().Contains(".Column(\"Blog_id\", DbType.Int32)"));
|
||||
|
||||
sw.GetStringBuilder().Clear();
|
||||
interpreter.Visit(bodyRecord);
|
||||
Assert.That(sw.ToString().Contains("SchemaBuilder.CreateTable(\"TEST_BodyRecord"));
|
||||
Assert.That(sw.ToString().Contains(".ContentPartVersionRecord()"));
|
||||
Assert.That(sw.ToString().Contains(".Column(\"Text\", DbType.String, column => column.WithLength(10000))"));
|
||||
Assert.That(sw.ToString().Contains(".Column(\"Format\", DbType.String, column => column.WithLength(42))"));
|
||||
Assert.That(!sw.ToString().Contains("ContentItemRecord_id"));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public class BlogRecord : ContentPartRecord {
|
||||
public virtual string Description { get; set; }
|
||||
public virtual int PostCount { get; set; }
|
||||
}
|
||||
|
||||
public class BodyRecord : ContentPartVersionRecord {
|
||||
[StringLengthMax]
|
||||
public virtual string Text { get; set; }
|
||||
[StringLength(42)]
|
||||
public virtual string Format { get; set; }
|
||||
}
|
||||
|
||||
public class BlogArchiveRecord {
|
||||
public virtual int Id { get; set; }
|
||||
public virtual BlogRecord Blog { get; set; }
|
||||
public virtual int Year { get; set; }
|
||||
public virtual int Month { get; set; }
|
||||
public virtual int PostCount { get; set; }
|
||||
}
|
||||
}
|
@ -181,6 +181,7 @@
|
||||
<Compile Include="ContentManagement\Records\GammaRecord.cs">
|
||||
<SubType>Code</SubType>
|
||||
</Compile>
|
||||
<Compile Include="DataMigration\SchemaCommandGeneratorTests.cs" />
|
||||
<Compile Include="DataMigration\SchemaBuilderTests.cs" />
|
||||
<Compile Include="DataMigration\DataMigrationTests.cs" />
|
||||
<Compile Include="DataMigration\Utilities\NullInterpreter.cs" />
|
||||
@ -254,6 +255,10 @@
|
||||
<Compile Include="Utility\ReflectTests.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Orchard.Web\Modules\Orchard.DevTools\Orchard.DevTools.csproj">
|
||||
<Project>{67C1D3AF-A0EC-46B2-BAE1-DF1DA8E0B890}</Project>
|
||||
<Name>Orchard.DevTools</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\Orchard.Web\Modules\Orchard.Users\Orchard.Users.csproj">
|
||||
<Project>{79AED36E-ABD0-4747-93D3-8722B042454B}</Project>
|
||||
<Name>Orchard.Users</Name>
|
||||
|
@ -1,4 +1,5 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Data;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using Orchard.Data.Migration.Interpreters;
|
||||
@ -16,7 +17,35 @@ namespace Orchard.DevTools.Services {
|
||||
_output.WriteLine("\t\t\t// Creating table {0}", command.Name);
|
||||
_output.WriteLine("\t\t\tSchemaBuilder.CreateTable(\"{0}\", table => table", command.Name);
|
||||
|
||||
|
||||
var matchContentPartRecord = command.TableCommands.OfType<CreateColumnCommand>().Any(
|
||||
c =>
|
||||
c.IsPrimaryKey
|
||||
&& c.ColumnName == "Id"
|
||||
&& !c.IsIdentity
|
||||
&& c.DbType == DbType.Int32);
|
||||
|
||||
var matchContentPartVersionRecord = matchContentPartRecord && command.TableCommands.OfType<CreateColumnCommand>().Any(
|
||||
c =>
|
||||
c.ColumnName == "ContentItemRecord_id"
|
||||
&& c.DbType == DbType.Int32);
|
||||
|
||||
if ( matchContentPartVersionRecord ) {
|
||||
_output.WriteLine("\t\t\t\t.ContentPartVersionRecord()");
|
||||
}
|
||||
else if ( matchContentPartRecord ) {
|
||||
_output.WriteLine("\t\t\t\t.ContentPartRecord()");
|
||||
}
|
||||
|
||||
foreach ( var createColumn in command.TableCommands.OfType<CreateColumnCommand>() ) {
|
||||
if(createColumn.ColumnName == "Id" && matchContentPartRecord) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if(createColumn.ColumnName == "ContentItemRecord_id" && matchContentPartVersionRecord) {
|
||||
continue;
|
||||
}
|
||||
|
||||
var type = createColumn.DbType.ToString();
|
||||
var field = createColumn.ColumnName;
|
||||
var options = new List<string>();
|
||||
@ -25,6 +54,10 @@ namespace Orchard.DevTools.Services {
|
||||
options.Add("PrimaryKey()");
|
||||
}
|
||||
|
||||
if ( createColumn.IsIdentity ) {
|
||||
options.Add("Identity()");
|
||||
}
|
||||
|
||||
if ( createColumn.IsUnique ) {
|
||||
options.Add("Unique()");
|
||||
}
|
||||
|
@ -1,22 +1,21 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Data;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using NHibernate.Cfg;
|
||||
using NHibernate.Mapping;
|
||||
using NHibernate.Tool.hbm2ddl;
|
||||
using Orchard.ContentManagement.Records;
|
||||
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;
|
||||
}
|
||||
|
||||
@ -30,7 +29,7 @@ namespace Orchard.Data.Migration.Generator {
|
||||
yield break;
|
||||
}
|
||||
|
||||
var configuration = _dataServicesProviderFactory.CreateProvider(parameters).BuildConfiguration(parameters);
|
||||
var configuration = _sessionFactoryHolder.GetConfiguration();
|
||||
Dialect.GetDialect(configuration.Properties);
|
||||
var mapping = configuration.BuildMapping();
|
||||
|
||||
@ -42,7 +41,10 @@ namespace Orchard.Data.Migration.Generator {
|
||||
|
||||
foreach(var table in tables.Where(t => parameters.RecordDescriptors.Any(rd => rd.Feature.Descriptor.Name == feature && rd.TableName == t.Name))) {
|
||||
string tableName = table.Name;
|
||||
if(tableName.StartsWith(prefix)) {
|
||||
var recordType = parameters.RecordDescriptors.Where(rd => rd.Feature.Descriptor.Name == feature && rd.TableName == tableName).First().Type;
|
||||
var isContentPart = typeof(ContentPartRecord).IsAssignableFrom(recordType);
|
||||
|
||||
if ( tableName.StartsWith(prefix) ) {
|
||||
tableName = tableName.Substring(prefix.Length);
|
||||
}
|
||||
|
||||
@ -59,10 +61,17 @@ namespace Orchard.Data.Migration.Generator {
|
||||
command.Column(column.Name, sqlType.DbType,
|
||||
action => {
|
||||
if (table1.PrimaryKey.Columns.Any(c => c.Name == column1.Name)) {
|
||||
action.PrimaryKey().Identity();
|
||||
action.PrimaryKey();
|
||||
|
||||
if ( !isContentPart ) {
|
||||
action.Identity();
|
||||
}
|
||||
}
|
||||
|
||||
if (column1.IsLengthDefined()) {
|
||||
|
||||
if ( column1.IsLengthDefined()
|
||||
&& new DbType[] { DbType.StringFixedLength, DbType.String, DbType.AnsiString, DbType.AnsiStringFixedLength }.Contains(sqlType.DbType)
|
||||
&& column1.Length != 255 ) {
|
||||
action.WithLength(column1.Length);
|
||||
}
|
||||
|
||||
@ -92,8 +101,7 @@ namespace Orchard.Data.Migration.Generator {
|
||||
/// Automatically updates a db to a functionning schema
|
||||
/// </summary>
|
||||
public void UpdateDatabase() {
|
||||
var parameters = _sessionFactoryHolder.GetSessionFactoryParameters();
|
||||
var configuration = _dataServicesProviderFactory.CreateProvider(parameters).BuildConfiguration(parameters);
|
||||
var configuration = _sessionFactoryHolder.GetConfiguration();
|
||||
new SchemaUpdate(configuration).Execute(false, true);
|
||||
}
|
||||
|
||||
@ -101,8 +109,7 @@ namespace Orchard.Data.Migration.Generator {
|
||||
/// Automatically creates a db with a functionning schema
|
||||
/// </summary>
|
||||
public void CreateDatabase() {
|
||||
var parameters = _sessionFactoryHolder.GetSessionFactoryParameters();
|
||||
var configuration = _dataServicesProviderFactory.CreateProvider(parameters).BuildConfiguration(parameters);
|
||||
var configuration = _sessionFactoryHolder.GetConfiguration();
|
||||
new SchemaExport(configuration).Execute(false, true, false);
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user