I am migrating a pre .net core FluentMIgrator project to the new .net core version. I had a custom VersionTable that looked like this:
[VersionTableMetaData]
public class VersionTable : DefaultVersionTableMetaData
{
public override string TableName => "T_SCHEMA_VERSION_INFO";
}
This results in the following warning/error:
VersionTable.cs(9,5,18,6): error CS0618: 'DefaultVersionTableMetaData.DefaultVersionTableMetaData()' is obsolete: 'Use dependency injection'
I fixed this error by changing my code to this (removed attribute & added constructor):
public class VersionTable : DefaultVersionTableMetaData
{
public VersionTable(IConventionSet conventionSet, IOptions<RunnerOptions> runnerOptions)
: base(conventionSet, runnerOptions)
{
SchemaName = "distribution";
}
public override string TableName => "T_SCHEMA_VERSION_INFO";
}
This compiles correctly. But then, I don't know what I have to add in my CreateServices function:
return new ServiceCollection()
.AddFluentMigratorCore()
.ConfigureRunner(rb => rb
.AddMySql5()
.WithVersionTable(new VersionTable(???))
So the WithVersionTable expects an instance of IVersionTableMetaData. Unfortunately, I don't know what to use for the convensionset and runnerOptions parameters.
Could you please provide some guidance and document them here? I have the feeling that this documentation is out of date.
You have two options:
IVersionTableMetaData directly (see example 2)The reason why example 2 works (and doesn't require a custom constructor) is because you're explicitly specifying a schema. The default version table must use the convention set to apply it.
I'll leave this issue open as a reminder to update the documentation.
services.AddScoped<IVersionTableMetaData, VersionTable>()
[VersionTableMetaData]
public class VersionTable : IVersionTableMetaData
{
public string ColumnName => "Version";
public string SchemaName => "distribution";
public string TableName => "T_SCHEMA_VERSION_INFO";
public string UniqueIndexName => "UC_Version";
public string AppliedOnColumnName => "AppliedOn";
public string DescriptionColumnName => "Description";
public object ApplicationContext { get; set; }
}
EDIT: Fixed examples
In Example 1, you still require an instance of versionTablemetaData to be instantiated. Therefore, it doesn't really work since my VersionTable constructor requires parameters.
In Example 2, you are not implementing the ApplicationContext property: https://github.com/fluentmigrator/fluentmigrator/blob/1b2779258a9eec466e8c5d00173f22e731314fb6/src/FluentMigrator.Runner.Core/VersionTableInfo/IVersionTableMetaData.cs#L34
Here's what I used instead:
services.AddScoped<IVersionTableMetaData, VersionTable>()
Would it be an option to simply remove the constructor parameters of DefaultVersionTableMetaData? This would solve all problems related to the instantiation of my VersionTable class. It would also make it possible to easily use the WithVersionTable method.
Yes, you're right. Registering it the way you did is correct. I fixed the examples.
I'll think about removing the constructor without requiring to apply the convention set at every place where the version table metadata is required.
Or, IMHO, a more elegant option would be to add a .WithVersionTable<VersionTable>() function. The implementation of this function would be something simple like:
public static IMigrationRunnerBuilder WithVersionTable<T>(
this IMigrationRunnerBuilder builder) where T:IVersionTableMetaData
{
builder.Services
.AddScoped<IVersionTableMetaDataAccessor, T>();
return builder;
}
It seems the resources here are not 100% correct. at least with net5
here is my complete working example
internal class VersionTableAccessor : IVersionTableMetaDataAccessor
{
public IVersionTableMetaData VersionTableMetaData { get; } = new VersionTable();
}
internal class VersionTable : IVersionTableMetaData
{
public object ApplicationContext { get; set; }
public string AppliedOnColumnName => "APPLIED_ON";
public string ColumnName => "VERSION";
public string DescriptionColumnName => "MIGRATION";
public bool OwnsSchema => true;
public string SchemaName => "MIG";
public string TableName => "HISTORY";
public string UniqueIndexName => "IX_HISTORY_VERSION";
}
internal static class MigrationExtensions
{
public static IMigrationRunnerBuilder WithVersionTable<T>(
this IMigrationRunnerBuilder builder)
where T: class, IVersionTableMetaDataAccessor
{
builder.Services.AddScoped<IVersionTableMetaDataAccessor, T>();
return builder;
}
}
and
services.AddFluentMigratorCore()
.ConfigureRunner(o => o.AddSqlServer()
.WithGlobalConnectionString("...")
.WithVersionTable<VersionTableAccessor>()
.ScanIn(typeof(Startup).Assembly).For.Migrations());
What problem are you getting?
Most helpful comment
Or, IMHO, a more elegant option would be to add a
.WithVersionTable<VersionTable>()function. The implementation of this function would be something simple like: