EntityFramework migrations become useless after switching to new Context. DbMigrator is using list of Pending Migrations from first database instance, which makes means no migrations are applied to other databases, which then leads to errors during Seed();
- C# .NET 4.5 MVC project with EF 6
- MS SQL Server 2014, multiple instances of same database model.
- CodeFirst approach with migrations.
- DbContext initializer is set to null.
On Application Start we have custom Db Initialization to create and update databases. CreateDatabaseIfNotExists
is working as intended, new databases have all migrations applied. However both MigrateDatabaseToLatestVersion
initializer and our custom one are failing to update databases other than first one on list.
foreach (var connectionString in connectionStrings)
{
using (var context = new ApplicationDbContext(connectionString))
{
//Create database
var created = context.Database.CreateIfNotExists();
var conf = new Workshop.Migrations.Configuration();
var migrator = new DbMigrator(conf);
migrator.Update();
//initial values
conf.RunSeed(context);
}
}
context.Database.CreateIfNotExists();
works correctly.migrator.GetLocalMigrations()
is always returning correct values.migrator.GetPendingMigrations()
after first database is returning empty list.migrator.GetDatabaseMigrations()
is mirror of pending migrations, after first database it contains full list event for empty databases.- Fetching data (
context.xxx.ToList()
) from Db instance confirms connection is up and working, and links to correct instance.
Forcing update to most recent migration with migrator.Update("migration_name");
changes nothing. From what I gather by reading EF source code, it checks pending migration list on its own, which gives it faulty results.
There seems to be some caching going in under the hood, but it eludes me how to reset it.
Is there a way to perform migrations on multiple databases or is it yet another "bug by design" in EF?
Edit:
Real problem is DbMigrator
creating new Context for its own use. It does it via default parameterless constructor, which in my case had fallback to default (first) connection string in web.Config
.
I do not see good solution for this problem but primitive workaround in my case is to temporarily edit default connection string:
var originalConStr = WebConfigurationManager.ConnectionStrings["ApplicationDbContext"].ConnectionString;
var setting = WebConfigurationManager.ConnectionStrings["ApplicationDbContext"];
var fi = typeof(ConfigurationElement).GetField("_bReadOnly", BindingFlags.Instance | BindingFlags.NonPublic);
//disable readonly flag on field
fi.SetValue(setting, false);
setting.ConnectionString = temporaryConnectionString; //now it works
//DO STUFF
setting.ConnectionString = originalConStr; //revert changes
Cheat from: How do I set a connection string config programatically in .net?
I still hope someone will find real solution so for now I will refrain with self-answer.