schambers/fluentmigrator — pull request #287 by Pathoschild (2012-08-02 16:41:28+00:00)
Title: Enable FluentMigrator extensibility with new IRunnerFactory

These changes let developers extend FluentMigrator in their application by creating an instance of `IRunnerFactory`, which constructs loader instances for FluentMigrator. If no factory is provided, FluentMigrator will automatically use the `DefaultRunnerFactory` which constructs the same objects as the current code does.

#### Example
We have a [multitenant](http://whatis.techtarget.com/definition/multi-tenancy) application which uses one schema per tenant, but FluentMigrator stores its version information once per database (in `dbo.versioninfo`). With the new code, we can easily override this default behaviour.

First, create a custom factory which overrides the behaviour we're interested in (the version loader). In this example, we use the [application context](https://github.com/schambers/fluentmigrator/wiki/ApplicationContext%3A-Passing-parameters-to-Migrations) to set the version table's schema.

```c#
///
Constructs implementations of FluentMigrator interfaces for the FluentMigrator runner.

[DesignedByContract]
public class CustomRunnerFactory : DefaultRunnerFactory
{
///
Get an object which reads and writes database versions to the database.

/// The migration runner used to create the version table.
/// The assembly to scan for migrations.
/// The default rules for migration mappings.
/// The arbitrary application context passed to the task runner.
[return: NotNull]
public override IVersionLoader GetVersionLoader([NotNull] IMigrationRunner runner, [NotNull] Assembly assembly, [NotNull] IMigrationConventions conventions, [NotNull, HasType(typeof(IRepositoryMetadata))] object applicationContext)
{
string schema = (applicationContext as IRepositoryMetadata).Schema;
IVersionTableMetaData tableMetadata = new ExplicitVersionTableMetaData
{
SchemaName = schema,
TableName = "repository.schemaversion",
ColumnName = "version",
UniqueIndexName = "uc_repository.schemaversion_version"
};
return new ExplicitVersionLoader(runner, assembly, conventions, tableMetadata);
}
}
```

Then just give the factory to the runner:
```c#
IRunnerContext context = new RunnerContext(this.Announcer)
{
...,
Task = "migrate:up",
ApplicationContext = this.Metadata,
Factory = new CustomRunnerFactory()
};
new TaskExecutor(context).Execute();
```

And now FluentMigrator handles migrations on a per-schema basis. Whee!

### Effects on current uses
This shouldn't affect any existing behaviour; by default the same objects are constructed, but they're done through the `DefaultRunnerFactory` instead of manually. We're successfully using the example above in our application, and all relevant unit tests pass. (A few tests fail due to missing dependencies like MySQL.)

The only significant change is that the `VersionLoader` now lazily initializes the version table, instead of doing it immediately in the constructor. This is needed to let custom implementations override the default behaviour in their own constructors. This shouldn't affect any existing behaviour, since the version information is accessed (and therefore initialized) early by the runners.