Выберите, какой DbContext автоматически мигрировать при запуске - PullRequest
1 голос
/ 15 марта 2019

Я работаю над небольшим пакетом многократного использования для приложений .NET Core, который поможет с автоматической миграцией при запуске приложения.

В основном он будет запускать Database.Migrate() на каждом DbContext.

Но дело в том, что я хочу запускать его только на DbContexts, который был «помечен» для автоматической миграции.Я думаю, что мог бы расширить AddDbContext и как-то сказать IServiceCollection отслеживать конкретный DbContext.Примерно так:

public static IServiceCollection AddDbContextWithMigration<TContext>(this IServiceCollection serviceCollection, Action<DbContextOptionsBuilder> optionsAction = null, ServiceLifetime contextLifetime = ServiceLifetime.Scoped, ServiceLifetime optionsLifetime = ServiceLifetime.Scoped) where TContext : DbContext
{
    //TODO: Somehow remember that this DbContext should be migrated.
    return serviceCollection.AddDbContext<TContext, TContext>(optionsAction, contextLifetime, optionsLifetime);
}

Использование:

public IServiceProvider ConfigureServices(IServiceCollection services)
{
    services.AddDbContextWithMigration<DbContext1>();
    services.AddDbContext<DbContext2>();
    services.AddDbContextWithMigration<DbContext3>();
}

Тогда я подумал, что могу либо использовать IStartupFilter, либо создать метод расширения для IApplicationBuilder.

С методом расширения:

public static IApplicationBuilder RunMigrations(this IApplicationBuilder app)
{
    if (app == null)
        throw new ArgumentNullException(nameof(app));

    var contexts = app.ApplicationServices.GetService();
    foreach (DbContext context in contexts)
    {
        context.Database.Migrate();
    }

    return app;
}

С IStartupFilter:

public class MigrationsFilter : IStartupFilter
{
    public Action<IApplicationBuilder> Configure(Action<IApplicationBuilder> next)
    {
        return builder =>
        {
            var contexts = builder.ApplicationServices.GetService();
            foreach (DbContext context in contexts)
            {
                context.Database.Migrate();
            }

            next(builder);
        };
    }
}

Поэтому у меня в основном два вопроса.

  1. Как мне сохранитьотслеживать, какие DbContexts должны быть перенесены?
  2. Это "правильное" использование IStartupFilter?

1 Ответ

0 голосов
/ 18 марта 2019

Я решил это, зарегистрировав класс-оболочку (IContextMigrator) для моих миграций.

Во-первых, мои методы расширения:

public static IApplicationBuilder RunMigrations(this IApplicationBuilder app)
{
    if (app == null)
        throw new ArgumentNullException(nameof(app));


    IEnumerable<IContextMigrator> migrations = app.ApplicationServices.GetServices<IContextMigrator>();

    foreach (IContextMigrator migration in migrations)
    {
        migration.Migrate();
        // Other logic for dispose...
    }

    return app;
}


public static IServiceCollection AddDbContextWithMigration<TContext>(this IServiceCollection serviceCollection, Action<DbContextOptionsBuilder> optionsAction = null, ServiceLifetime contextLifetime = ServiceLifetime.Scoped, ServiceLifetime optionsLifetime = ServiceLifetime.Scoped) where TContext : DbContext
{
    // By simply registering a transient of a wrapper-class I can resolve it later.
    serviceCollection.AddTransient<IContextMigrator, ContextMigrator<TContext>>();
    return serviceCollection.AddDbContext<TContext, TContext>(optionsAction, contextLifetime, optionsLifetime);
}

Тогда мой класс для фактической миграции:

public interface IContextMigrator : IDisposable
{
    void Migrate();
}

/// <summary>
/// Class responsible for migration of a DbContext.
/// Used by ApplicationBuilderExtensions to perform migrations.
/// </summary>
/// <typeparam name="T"></typeparam>
internal sealed class ContextMigrator<T> : IContextMigrator
    where T : DbContext
{
    private readonly T context;

    public ContextMigrator(T context)
    {
        this.context = context;
    }

    public void Migrate()
    {
        try
        {
            this.context.Database.Migrate();
        }
        catch (Exception e)
        {
            throw new MigrationException(context.GetType().Name, e);
        }
    }

    public void Dispose()
    {

    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...