added better db migration support than what Subsonic provides out of the box.

This commit is contained in:
kay.one
2011-05-23 17:34:57 -07:00
parent 180da4c82a
commit ce63f05512
91 changed files with 7218 additions and 48 deletions

View File

@@ -0,0 +1,110 @@
using Migrator.Framework;
using System.Collections.Generic;
namespace Migrator
{
public abstract class BaseMigrate
{
protected readonly ITransformationProvider _provider;
protected ILogger _logger;
protected List<long> _availableMigrations;
protected List<long> _original;
protected long _current;
protected bool _dryrun;
protected BaseMigrate(List<long> availableMigrations, ITransformationProvider provider, ILogger logger)
{
_provider = provider;
_availableMigrations = availableMigrations;
_original = new List<long> (_provider.AppliedMigrations.ToArray()); //clone
_logger = logger;
}
public static BaseMigrate GetInstance(List<long> availableMigrations, ITransformationProvider provider, ILogger logger)
{
return new MigrateAnywhere(availableMigrations, provider, logger);
}
public List<long> AppliedVersions
{
get { return _original; }
}
public virtual long Current
{
get { return _current; }
protected set { _current = value; }
}
public virtual bool DryRun
{
get { return _dryrun; }
set { _dryrun = value; }
}
public abstract long Previous { get; }
public abstract long Next { get; }
public void Iterate()
{
Current = Next;
}
public abstract bool Continue(long targetVersion);
public abstract void Migrate(IMigration migration);
/// <summary>
/// Finds the next migration available to be applied. Only returns
/// migrations that have NOT already been applied.
/// </summary>
/// <returns>The migration number of the next available Migration.</returns>
protected long NextMigration()
{
// Start searching at the current index
int migrationSearch = _availableMigrations.IndexOf(Current)+1;
// See if we can find a migration that matches the requirement
while(migrationSearch < _availableMigrations.Count
&& _provider.AppliedMigrations.Contains(_availableMigrations[migrationSearch]))
{
migrationSearch++;
}
// did we exhaust the list?
if(migrationSearch == _availableMigrations.Count){
// we're at the last one. Done!
return _availableMigrations[migrationSearch-1]+1;
}
// found one.
return _availableMigrations[migrationSearch];
}
/// <summary>
/// Finds the previous migration that has been applied. Only returns
/// migrations that HAVE already been applied.
/// </summary>
/// <returns>The most recently applied Migration.</returns>
protected long PreviousMigration()
{
// Start searching at the current index
int migrationSearch = _availableMigrations.IndexOf(Current)-1;
// See if we can find a migration that matches the requirement
while(migrationSearch > -1
&& !_provider.AppliedMigrations.Contains(_availableMigrations[migrationSearch]))
{
migrationSearch--;
}
// did we exhaust the list?
if(migrationSearch < 0){
// we're at the first one. Done!
return 0;
}
// found one.
return _availableMigrations[migrationSearch];
}
}
}

View File

@@ -0,0 +1,118 @@
using System;
using System.CodeDom.Compiler;
using System.Collections.Generic;
using System.IO;
using System.Reflection;
using Migrator.Framework;
namespace Migrator.Compile
{
public class ScriptEngine
{
public readonly string[] extraReferencedAssemblies;
private readonly CodeDomProvider _provider;
private string _codeType = "csharp";
public ScriptEngine() : this(null, null)
{
}
public ScriptEngine(string[] extraReferencedAssemblies)
: this(null, extraReferencedAssemblies)
{
}
public ScriptEngine(string codeType, string[] extraReferencedAssemblies)
{
if (!String.IsNullOrEmpty(codeType))
_codeType = codeType;
this.extraReferencedAssemblies = extraReferencedAssemblies;
// There is currently no way to generically create a CodeDomProvider and have it work with .NET 3.5
_provider = CodeDomProvider.CreateProvider(_codeType);
}
public Assembly Compile(string directory)
{
string[] files = GetFilesRecursive(directory);
Console.Out.WriteLine("Compiling:");
Array.ForEach(files, delegate(String file) { Console.Out.WriteLine(file); });
return Compile(files);
}
private string[] GetFilesRecursive(string directory)
{
FileInfo[] files = GetFilesRecursive(new DirectoryInfo(directory));
string[] fileNames = new string[files.Length];
for (int i = 0; i < files.Length; i ++)
{
fileNames[i] = files[i].FullName;
}
return fileNames;
}
private FileInfo[] GetFilesRecursive(DirectoryInfo d)
{
List<FileInfo> files = new List<FileInfo>();
files.AddRange(d.GetFiles(String.Format("*.{0}", _provider.FileExtension)));
DirectoryInfo[] subDirs = d.GetDirectories();
if (subDirs.Length > 0)
{
foreach (DirectoryInfo subDir in subDirs)
{
files.AddRange(GetFilesRecursive(subDir));
}
}
return files.ToArray();
}
public Assembly Compile(params string[] files)
{
CompilerParameters parms = SetupCompilerParams();
CompilerResults compileResult = _provider.CompileAssemblyFromFile(parms, files);
if (compileResult.Errors.Count != 0)
{
foreach (CompilerError err in compileResult.Errors)
{
Console.Error.WriteLine("{0} ({1}:{2}) {3}", err.FileName, err.Line, err.Column, err.ErrorText);
}
}
return compileResult.CompiledAssembly;
}
private CompilerParameters SetupCompilerParams()
{
string migrationFrameworkPath = FrameworkAssemblyPath();
CompilerParameters parms = new CompilerParameters();
parms.CompilerOptions = "/t:library";
parms.GenerateInMemory = true;
parms.IncludeDebugInformation = true;
parms.OutputAssembly = Path.Combine(Path.GetDirectoryName(migrationFrameworkPath), "MyMigrations.dll");
Console.Out.WriteLine("Output assembly: " + parms.OutputAssembly);
// Add Default referenced assemblies
parms.ReferencedAssemblies.Add("mscorlib.dll");
parms.ReferencedAssemblies.Add("System.dll");
parms.ReferencedAssemblies.Add("System.Data.dll");
parms.ReferencedAssemblies.Add(FrameworkAssemblyPath());
if (null != extraReferencedAssemblies && extraReferencedAssemblies.Length > 0)
{
Array.ForEach(extraReferencedAssemblies,
delegate(String assemb) { parms.ReferencedAssemblies.Add(assemb); });
}
return parms;
}
private static string FrameworkAssemblyPath()
{
string path = typeof (MigrationAttribute).Module.FullyQualifiedName;
Console.Out.WriteLine("Framework DLL: " + path);
return path;
}
}
}

View File

@@ -0,0 +1,26 @@
#region License
//The contents of this file are subject to the Mozilla Public License
//Version 1.1 (the "License"); you may not use this file except in
//compliance with the License. You may obtain a copy of the License at
//http://www.mozilla.org/MPL/
//Software distributed under the License is distributed on an "AS IS"
//basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
//License for the specific language governing rights and limitations
//under the License.
#endregion
using System;
namespace Migrator
{
/// <summary>
/// Exception thrown when a migration number is not unique.
/// </summary>
public class DuplicatedVersionException : Exception
{
public DuplicatedVersionException(long version)
: base(String.Format("Migration version #{0} is duplicated", version))
{
}
}
}

View File

@@ -0,0 +1,26 @@
#region License
//The contents of this file are subject to the Mozilla Public License
//Version 1.1 (the "License"); you may not use this file except in
//compliance with the License. You may obtain a copy of the License at
//http://www.mozilla.org/MPL/
//Software distributed under the License is distributed on an "AS IS"
//basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
//License for the specific language governing rights and limitations
//under the License.
#endregion
using System;
namespace Migrator
{
/// <summary>
/// Exception thrown in a migration <c>Down()</c> method
/// when changes can't be undone.
/// </summary>
public class IrreversibleMigrationException : Exception
{
public IrreversibleMigrationException() : base("Irreversible migration")
{
}
}
}

View File

@@ -0,0 +1,99 @@
using System;
using System.Collections.Generic;
using Migrator.Framework;
namespace Migrator
{
/// <summary>
/// Description of MigrateAnywhere.
/// </summary>
public class MigrateAnywhere : BaseMigrate
{
private bool _goForward;
public MigrateAnywhere(List<long> availableMigrations, ITransformationProvider provider, ILogger logger)
: base(availableMigrations, provider, logger)
{
_current = 0;
if (provider.AppliedMigrations.Count > 0) {
_current = provider.AppliedMigrations[provider.AppliedMigrations.Count - 1];
}
_goForward = false;
}
public override long Next
{
get
{
return _goForward
? NextMigration()
: PreviousMigration();
}
}
public override long Previous
{
get
{
return _goForward
? PreviousMigration()
: NextMigration();
}
}
public override bool Continue(long version)
{
// If we're going backwards and our current is less than the target,
// reverse direction. Also, start over at zero to make sure we catch
// any merged migrations that are less than the current target.
if (!_goForward && version >= Current)
{
_goForward = true;
Current = 0;
Iterate();
}
// We always finish on going forward. So continue if we're still
// going backwards, or if there are no migrations left in the forward direction.
return !_goForward || Current <= version;
}
public override void Migrate(IMigration migration)
{
_provider.BeginTransaction();
MigrationAttribute attr = (MigrationAttribute)Attribute.GetCustomAttribute(migration.GetType(), typeof(MigrationAttribute));
if (_provider.AppliedMigrations.Contains(attr.Version)) {
RemoveMigration(migration, attr);
} else {
ApplyMigration(migration, attr);
}
}
private void ApplyMigration(IMigration migration, MigrationAttribute attr)
{
// we're adding this one
_logger.MigrateUp(Current, migration.Name);
if(! DryRun)
{
migration.Up();
_provider.MigrationApplied(attr.Version);
_provider.Commit();
migration.AfterUp();
}
}
private void RemoveMigration(IMigration migration, MigrationAttribute attr)
{
// we're removing this one
_logger.MigrateDown(Current, migration.Name);
if (! DryRun)
{
migration.Down();
_provider.MigrationUnApplied(attr.Version);
_provider.Commit();
migration.AfterDown();
}
}
}
}

View File

View File

View File

@@ -0,0 +1,43 @@
#region License
//The contents of this file are subject to the Mozilla Public License
//Version 1.1 (the "License"); you may not use this file except in
//compliance with the License. You may obtain a copy of the License at
//http://www.mozilla.org/MPL/
//Software distributed under the License is distributed on an "AS IS"
//basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
//License for the specific language governing rights and limitations
//under the License.
#endregion
using System;
using System.Collections.Generic;
using Migrator.Framework;
namespace Migrator
{
/// <summary>
/// Comparer of Migration by their version attribute.
/// </summary>
public class MigrationTypeComparer : IComparer<Type>
{
private readonly bool _ascending = true;
public MigrationTypeComparer(bool ascending)
{
_ascending = ascending;
}
public int Compare(Type x, Type y)
{
MigrationAttribute attribOfX = (MigrationAttribute) Attribute.GetCustomAttribute(x, typeof(MigrationAttribute));
MigrationAttribute attribOfY = (MigrationAttribute) Attribute.GetCustomAttribute(y, typeof(MigrationAttribute));
if (_ascending)
return attribOfX.Version.CompareTo(attribOfY.Version);
else
return attribOfY.Version.CompareTo(attribOfX.Version);
}
}
}

View File

@@ -0,0 +1,136 @@
using System;
using System.Collections.Generic;
using System.Reflection;
using Migrator.Framework;
namespace Migrator
{
/// <summary>
/// Handles inspecting code to find all of the Migrations in assemblies and reading
/// other metadata such as the last revision, etc.
/// </summary>
public class MigrationLoader
{
private readonly ITransformationProvider _provider;
private readonly List<Type> _migrationsTypes = new List<Type>();
public MigrationLoader(ITransformationProvider provider, Assembly migrationAssembly, bool trace)
{
_provider = provider;
AddMigrations(migrationAssembly);
if (trace)
{
provider.Logger.Trace("Loaded migrations:");
foreach (Type t in _migrationsTypes)
{
provider.Logger.Trace("{0} {1}", GetMigrationVersion(t).ToString().PadLeft(5), StringUtils.ToHumanName(t.Name));
}
}
}
public void AddMigrations(Assembly migrationAssembly)
{
if (migrationAssembly != null)
_migrationsTypes.AddRange(GetMigrationTypes(migrationAssembly));
}
/// <summary>
/// Returns registered migration <see cref="System.Type">types</see>.
/// </summary>
public List<Type> MigrationsTypes
{
get { return _migrationsTypes; }
}
/// <summary>
/// Returns the last version of the migrations.
/// </summary>
public long LastVersion
{
get
{
if (_migrationsTypes.Count == 0)
return 0;
return GetMigrationVersion(_migrationsTypes[_migrationsTypes.Count - 1]);
}
}
/// <summary>
/// Check for duplicated version in migrations.
/// </summary>
/// <exception cref="CheckForDuplicatedVersion">CheckForDuplicatedVersion</exception>
public void CheckForDuplicatedVersion()
{
List<long> versions = new List<long>();
foreach (Type t in _migrationsTypes)
{
long version = GetMigrationVersion(t);
if (versions.Contains(version))
throw new DuplicatedVersionException(version);
versions.Add(version);
}
}
/// <summary>
/// Collect migrations in one <c>Assembly</c>.
/// </summary>
/// <param name="asm">The <c>Assembly</c> to browse.</param>
/// <returns>The migrations collection</returns>
public static List<Type> GetMigrationTypes(Assembly asm)
{
List<Type> migrations = new List<Type>();
foreach (Type t in asm.GetExportedTypes())
{
MigrationAttribute attrib =
(MigrationAttribute) Attribute.GetCustomAttribute(t, typeof (MigrationAttribute));
if (attrib != null && typeof(IMigration).IsAssignableFrom(t) && !attrib.Ignore)
{
migrations.Add(t);
}
}
migrations.Sort(new MigrationTypeComparer(true));
return migrations;
}
/// <summary>
/// Returns the version of the migration
/// <see cref="MigrationAttribute">MigrationAttribute</see>.
/// </summary>
/// <param name="t">Migration type.</param>
/// <returns>Version number sepcified in the attribute</returns>
public static long GetMigrationVersion(Type t)
{
MigrationAttribute attrib = (MigrationAttribute)
Attribute.GetCustomAttribute(t, typeof(MigrationAttribute));
return attrib.Version;
}
public List<long> GetAvailableMigrations()
{
//List<int> availableMigrations = new List<int>();
_migrationsTypes.Sort(new MigrationTypeComparer(true));
return _migrationsTypes.ConvertAll(new Converter<Type, long>(GetMigrationVersion));
}
public IMigration GetMigration(long version)
{
foreach (Type t in _migrationsTypes)
{
if (GetMigrationVersion(t) == version)
{
IMigration migration = (IMigration)Activator.CreateInstance(t);
migration.Database = _provider;
return migration;
}
}
return null;
}
}
}

View File

@@ -0,0 +1,177 @@
#region License
//The contents of this file are subject to the Mozilla Public License
//Version 1.1 (the "License"); you may not use this file except in
//compliance with the License. You may obtain a copy of the License at
//http://www.mozilla.org/MPL/
//Software distributed under the License is distributed on an "AS IS"
//basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
//License for the specific language governing rights and limitations
//under the License.
#endregion
using System;
using System.Collections.Generic;
using System.Reflection;
using Migrator.Framework;
using Migrator.Framework.Loggers;
namespace Migrator
{
/// <summary>
/// Migrations mediator.
/// </summary>
public class Migrator
{
private readonly ITransformationProvider _provider;
private readonly MigrationLoader _migrationLoader;
private ILogger _logger = new Logger(false);
protected bool _dryrun;
private string[] _args;
public string[] args
{
get { return _args; }
set { _args = value; }
}
public Migrator(string provider, string connectionString, Assembly migrationAssembly)
: this(provider, connectionString, migrationAssembly, false)
{
}
public Migrator(string provider, string connectionString, Assembly migrationAssembly, bool trace)
: this(ProviderFactory.Create(provider, connectionString), migrationAssembly, trace)
{
}
public Migrator(string provider, string connectionString, Assembly migrationAssembly, bool trace, ILogger logger)
: this(ProviderFactory.Create(provider, connectionString), migrationAssembly, trace, logger)
{
}
public Migrator(ITransformationProvider provider, Assembly migrationAssembly, bool trace)
: this(provider, migrationAssembly, trace, new Logger(trace, new ConsoleWriter()))
{
}
public Migrator(ITransformationProvider provider, Assembly migrationAssembly, bool trace, ILogger logger)
{
_provider = provider;
Logger = logger;
_migrationLoader = new MigrationLoader(provider, migrationAssembly, trace);
_migrationLoader.CheckForDuplicatedVersion();
}
/// <summary>
/// Returns registered migration <see cref="System.Type">types</see>.
/// </summary>
public List<Type> MigrationsTypes
{
get { return _migrationLoader.MigrationsTypes; }
}
/// <summary>
/// Run all migrations up to the latest. Make no changes to database if
/// dryrun is true.
/// </summary>
public void MigrateToLastVersion()
{
MigrateTo(_migrationLoader.LastVersion);
}
/// <summary>
/// Returns the current migrations applied to the database.
/// </summary>
public List<long> AppliedMigrations
{
get { return _provider.AppliedMigrations; }
}
/// <summary>
/// Get or set the event logger.
/// </summary>
public ILogger Logger
{
get { return _logger; }
set
{
_logger = value;
_provider.Logger = value;
}
}
public virtual bool DryRun
{
get { return _dryrun; }
set { _dryrun = value; }
}
/// <summary>
/// Migrate the database to a specific version.
/// Runs all migration between the actual version and the
/// specified version.
/// If <c>version</c> is greater then the current version,
/// the <c>Up()</c> method will be invoked.
/// If <c>version</c> lower then the current version,
/// the <c>Down()</c> method of previous migration will be invoked.
/// If <c>dryrun</c> is set, don't write any changes to the database.
/// </summary>
/// <param name="version">The version that must became the current one</param>
public void MigrateTo(long version)
{
if (_migrationLoader.MigrationsTypes.Count == 0)
{
_logger.Warn("No public classes with the Migration attribute were found.");
return;
}
bool firstRun = true;
BaseMigrate migrate = BaseMigrate.GetInstance(_migrationLoader.GetAvailableMigrations(), _provider, _logger);
migrate.DryRun = DryRun;
Logger.Started(migrate.AppliedVersions, version);
while (migrate.Continue(version))
{
IMigration migration = _migrationLoader.GetMigration(migrate.Current);
if (null == migration)
{
_logger.Skipping(migrate.Current);
migrate.Iterate();
continue;
}
try
{
if (firstRun)
{
migration.InitializeOnce(_args);
firstRun = false;
}
migrate.Migrate(migration);
}
catch (Exception ex)
{
Logger.Exception(migrate.Current, migration.Name, ex);
// Oho! error! We rollback changes.
Logger.RollingBack(migrate.Previous);
_provider.Rollback();
throw;
}
migrate.Iterate();
}
Logger.Finished(migrate.AppliedVersions, version);
}
}
}

View File

@@ -0,0 +1,76 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="4.0">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProductVersion>9.0.30729</ProductVersion>
<SchemaVersion>2.0</SchemaVersion>
<ProjectGuid>{1FEE70A4-AAD7-4C60-BE60-3F7DC03A8C4D}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>Migrator</RootNamespace>
<AssemblyName>Migrator</AssemblyName>
<FileUpgradeFlags>
</FileUpgradeFlags>
<OldToolsVersion>3.5</OldToolsVersion>
<UpgradeBackupLocation>
</UpgradeBackupLocation>
<SignAssembly>true</SignAssembly>
<AssemblyOriginatorKeyFile>MigratorDotNet.snk</AssemblyOriginatorKeyFile>
<TargetFrameworkVersion>v2.0</TargetFrameworkVersion>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Migrator\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Migrator\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Data" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="..\config\AssemblyInfo.cs">
<Link>AssemblyInfo.cs</Link>
</Compile>
<Compile Include="BaseMigrate.cs" />
<Compile Include="Compile\ScriptEngine.cs" />
<Compile Include="DuplicatedVersionException.cs" />
<Compile Include="IrreversibleMigrationException.cs" />
<Compile Include="MigrateAnywhere.cs" />
<Compile Include="MigrationComparer.cs" />
<Compile Include="MigrationLoader.cs" />
<Compile Include="Migrator.cs" />
<Compile Include="ProviderFactory.cs" />
<Compile Include="Tools\SchemaDumper.cs" />
</ItemGroup>
<ItemGroup>
<None Include="MigratorDotNet.snk" />
</ItemGroup>
<ItemGroup>
<Service Include="{B4F97281-0DBD-4835-9ED8-7DFB966E87FF}" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Migrator.Framework\Migrator.Framework.csproj">
<Project>{5270F048-E580-486C-B14C-E5B9F6E539D4}</Project>
<Name>Migrator.Framework</Name>
</ProjectReference>
<ProjectReference Include="..\Migrator.Providers\Migrator.Providers.csproj">
<Project>{D58C68E4-D789-40F7-9078-C9F587D4363C}</Project>
<Name>Migrator.Providers</Name>
</ProjectReference>
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
</Project>

Binary file not shown.

View File

@@ -0,0 +1,75 @@
#region License
//The contents of this file are subject to the Mozilla Public License
//Version 1.1 (the "License"); you may not use this file except in
//compliance with the License. You may obtain a copy of the License at
//http://www.mozilla.org/MPL/
//Software distributed under the License is distributed on an "AS IS"
//basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
//License for the specific language governing rights and limitations
//under the License.
#endregion
using System;
using System.Collections.Generic;
using System.Reflection;
using Migrator.Framework;
using Migrator.Providers;
namespace Migrator
{
/// <summary>
/// Handles loading Provider implementations
/// </summary>
public class ProviderFactory
{
private static readonly Assembly providerAssembly;
private static readonly Dictionary<String, object> dialects = new Dictionary<string, object>();
static ProviderFactory()
{
//string directory = Path.GetDirectoryName(Assembly.GetExecutingAssembly().CodeBase);
//string fullPath = Path.Combine(directory, "Migrator.Providers.dll");
//if (fullPath.StartsWith("file:\\"))
// fullPath = fullPath.Substring(6);
//else if (fullPath.StartsWith("file:"))
// fullPath = fullPath.Substring(5);
providerAssembly = Assembly.GetAssembly(typeof(TransformationProvider));
//providerAssembly = Assembly.LoadFrom("Migrator.Providers.dll");
LoadDialects();
}
public static ITransformationProvider Create(string providerName, string connectionString)
{
object dialectInstance = DialectForProvider(providerName);
MethodInfo mi = dialectInstance.GetType().GetMethod("NewProviderForDialect", new Type[] {typeof (String)});
return (ITransformationProvider)mi.Invoke(dialectInstance, new object[] { connectionString });
}
public static object DialectForProvider(string providerName)
{
if (String.IsNullOrEmpty(providerName))
return null;
foreach (string key in dialects.Keys)
{
if (0 < key.IndexOf(providerName, StringComparison.InvariantCultureIgnoreCase))
return dialects[key];
}
return null;
}
public static void LoadDialects()
{
Type dialectType = providerAssembly.GetType("Migrator.Providers.Dialect");
foreach (Type t in providerAssembly.GetTypes())
{
if (t.IsSubclassOf(dialectType))
{
dialects.Add(t.FullName, Activator.CreateInstance(t, null));
}
}
}
}
}

View File

@@ -0,0 +1,70 @@
#region License
//The contents of this file are subject to the Mozilla Public License
//Version 1.1 (the "License"); you may not use this file except in
//compliance with the License. You may obtain a copy of the License at
//http://www.mozilla.org/MPL/
//Software distributed under the License is distributed on an "AS IS"
//basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
//License for the specific language governing rights and limitations
//under the License.
#endregion
using System.IO;
using Migrator.Framework;
namespace Migrator.Tools
{
public class SchemaDumper
{
private readonly ITransformationProvider _provider;
public SchemaDumper(string provider, string connectionString)
{
_provider = ProviderFactory.Create(provider, connectionString);
}
public string Dump()
{
StringWriter writer = new StringWriter();
writer.WriteLine("using Migrator;\n");
writer.WriteLine("[Migration(1)]");
writer.WriteLine("public class SchemaDump : Migration");
writer.WriteLine("{");
writer.WriteLine("\tpublic override void Up()");
writer.WriteLine("\t{");
foreach (string table in _provider.GetTables())
{
writer.WriteLine("\t\tDatabase.AddTable(\"{0}\",", table);
foreach (Column column in _provider.GetColumns(table))
{
writer.WriteLine("\t\t\tnew Column(\"{0}\", typeof({1})),", column.Name, column.Type);
}
writer.WriteLine("\t\t);");
}
writer.WriteLine("\t}\n");
writer.WriteLine("\tpublic override void Down()");
writer.WriteLine("\t{");
foreach (string table in _provider.GetTables())
{
writer.WriteLine("\t\tDatabase.RemoveTable(\"{0}\");", table);
}
writer.WriteLine("\t}");
writer.WriteLine("}");
return writer.ToString();
}
public void DumpTo(string file)
{
using (StreamWriter writer = new StreamWriter(file))
{
writer.Write(Dump());
}
}
}
}