实体框架:使用多个自定义历史上下文

本文关键字:自定义 历史 历史上 上下文 框架 实体 | 更新日期: 2023-09-27 18:11:29

我有映射__MigrationHistory到现有数据库表的代码。

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"));
        }
    }
}

我还有另一个自定义历史上下文:

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"));
        }
    }
}

我在代码中调用它:

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

我有多个数据库,它们有自己的自定义迁移历史上下文。如何让迁移历史的数据库初始化程序选择它们将使用哪个历史上下文?

实体框架:使用多个自定义历史上下文

我有一个系统,在两个不同的程序集中有两个不同的DbContext子类,这两个上下文使用两个不同的HistoryContexts。我的诀窍是使用两个不同的HistoryContext ,并确保每个DbContext子类的DbMigrationsConfiguration子类包含在数据库初始化时注册正确HistoryContext子类的代码。

基本数据库迁移类:

   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));
    }
}

示例上下文特定的迁移配置类:

    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";
    }
}

然后在我的数据库初始化程序中,我确保迁移配置在初始化时实例化…

    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();
    }
} 

我首先运行6.2.0的代码。我只是为每个DbContext使用不同的模式

在DbContext中,我设置了默认模式

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

这会导致每个DbContext都有一个单独的__MigrationHistory表

您必须在上下文上方添加属性,就像这样:

[DbConfigurationType(typeof(CustomeConfiguration))]

然后尝试在全局asax或应用配置中初始化上下文之前注册配置。

DbConfiguration.SetConfiguration(new TDBConfigurations());

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