1

I have the code that map the __MigrationHistory to the existing database table.

namespace Alvin_CMS.Migrations
{
    public class CustomHistoryContext : HistoryContext
    {
        public CustomHistoryContext(DbConnection dbConnection, string defaultSchema)
        : base(dbConnection, defaultSchema)
        {
        }

        protected override void OnModelCreating(DbModelBuilder modelBuilder)
        {
            base.OnModelCreating(modelBuilder);
            modelBuilder.Entity<HistoryRow>().ToTable(tableName: "__MigrationHistory", schemaName: "dbo");
            //modelBuilder.Entity<HistoryRow>().Property(p => p.MigrationId).HasColumnName("Migration_ID");
        }
    }

    public class CustomHistoryConfiguration : DbConfiguration
    {
        public CustomHistoryConfiguration()
        {
            this.SetHistoryContext("System.Data.SqlClient",
            (connection, defaultSchema) => new CustomHistoryContext(connection, "dbo"));
        }
    }
}

Also I have another custom history context:

namespace EAccounting.Migrations
{
    public class CustomHistoryContext : HistoryContext
    {
        public CustomHistoryContext(DbConnection dbConnection, string defaultSchema)
            : base(dbConnection, defaultSchema)
        {
        }

        protected override void OnModelCreating(DbModelBuilder modelBuilder)
        {
            base.OnModelCreating(modelBuilder);
            modelBuilder.Entity<HistoryRow>().ToTable(tableName: "__MigrationHistory", schemaName: "EAccounting");
            //modelBuilder.Entity<HistoryRow>().Property(p => p.MigrationId).HasColumnName("Migration_ID");
        }
    }

    public class CustomHistoryConfiguration : DbConfiguration
    {
        public CustomHistoryConfiguration()
        {
            this.SetHistoryContext("System.Data.SqlClient",
            (connection, defaultSchema) => new CustomHistoryContext(connection, "EAccounting"));
        }
    }
}

And I call this in my code:

Database.SetInitializer(new MigrateDatabaseToLatestVersion<EAccounting.Models.EAccountingMigrationDBContext, EAccounting.Migrations.Configuration>()); 

I have multiple databases which have their own custom migration history context. How can I let the database initializer for the migration history to choose which history context they will use?

3 Answers 3

1

I have a system with two different DbContext subclasses in two different assemblies, and these two contexts use two different HistoryContexts. The trick for me was to use two different HistoryContext tables, and to ensure that the DbMigrationsConfiguration subclass for each DbContext subclass includes code that registers the right HistoryContext subclass when the database initializes.

base db migration class:

   public class DbMigrationsConfigurationBase<TContext> : DbMigrationsConfiguration<TContext>, IDbMigrationsConfiguration<TContext> where TContext : DbContext, IDbContext
{
    public DbMigrationsConfigurationBase(Func<DbConnection, string, HistoryContext> historyContextFactory)
    {
        AutomaticMigrationsEnabled = true;
        AutomaticMigrationDataLossAllowed = true;
        MigrationsDirectory = @"Migrations";
        RegisterHistoryContextFactory(historyContextFactory);
    }

    private void RegisterHistoryContextFactory(Func<DbConnection, string, HistoryContext> historyContextFactory)
    {
        foreach (ConnectionStringSettings connectionString in ConfigurationManager.ConnectionStrings)
        {
            if (!string.IsNullOrEmpty(connectionString.ProviderName))
            {
                SetHistoryContextFactory(connectionString.ProviderName, historyContextFactory);
            }
        }
    }

    public IDbMigrator GetMigrator()
    {
        return new DbMigratorWrapper(new DbMigrator(this));
    }
}

Example context-specific migration config class:

    public sealed class MySpecialDatabaseMigrationConfiguration : DbMigrationsConfigurationBase<MySpecialDatabase>
{
    private static readonly Func<DbConnection, string, HistoryContext> HistoryContextFactory =
        (connection, schema) => new MySpecialDatabaseHistoryContext(connection, schema);
    public MySpecialDatabaseMigrationConfiguration(): base(HistoryContextFactory)
    {
        ContextKey = "MyNamespace.MySpecialDatabase";
    }
}

Then in my database initializer I ensure the migration config is instantiated at initialization time...

    public class CreateOrMigrateDatabaseInitializer<TContext, TConfiguration> : IDatabaseInitializer<TContext>
    where TContext : DbContext, IDbContext
    where TConfiguration : IDbMigrationsConfiguration<TContext>, new()
{
    private readonly string _connection;

    public CreateOrMigrateDatabaseInitializer(string connection, ILogger logger = null)
    {
        Contract.Requires(!string.IsNullOrEmpty(connection), "connection");
        _connection = connection;
    }

    public void InitializeDatabase(TContext context)
    {
        Contract.Requires(context != null, "context");

        IDbMigrationsConfiguration<TContext> configuration = new TConfiguration()
        {
            TargetDatabase = new DbConnectionInfo(_connection)
        };

        if (!context.Database.Exists() || !context.Database.CompatibleWithModel(throwIfNoMetadata: false))
        {
            var migrator = configuration.GetMigrator();

            foreach (string s in migrator.GetPendingMigrations())
            {
                migrator.Update(s);
            }
        }

        Seed(context);

        context.SaveChanges();
    }

} 
Sign up to request clarification or add additional context in comments.

Comments

0

I am running 6.2.0 with code first. I just use a different schema for each DbContext

Inside the DbContext I set the default schema

  protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        modelBuilder.HasDefaultSchema("schema1");
    }

this causes a separate __MigrationHistory table for each DbContext

Comments

0

You have to add attribute above the context, juts like this:

[DbConfigurationType(typeof(CustomeConfiguration))]

Then try to register the configuration before initialize the context in global asax or in the app config.

DbConfiguration.SetConfiguration(new TDBConfigurations());

Reference: https://learn.microsoft.com/en-us/ef/ef6/fundamentals/configuring/code-based

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.