Enity Framework 6.0.0.0: Failed to create explicit migration ... with code based migration

The situation is as follows:

  • Per tenant db.
  • Code-based manual migration. The initial creation of dbs is also done using Code First. There are no existing dbs in the current scenario.
  • The exact db is not known during the migration script generation, because there are a lot of them. The only thing I have is the code - the initial migration of the script based on the model at the beginning and the model with some changes.
  • Existing dbs generated using the initial script - everything works fine. This is how I reproduce the problem:
  • Run the PS command: Add-Migration -Name Initial -StartUpProjectName MyApp.Web -ProjectName MyApp.Migrations -ConfigurationTypeName "MyApp.Migrations.MyMigrationConfiguration" -ConnectionString "Data Source =. \ SQLEXPRESS; Database = demo_Connection; ID = x; Password = x "-ConnectionProviderName" System.Data.SqlClient "- works fine
  • Run the application and create db. Stop the application. Make changes to the model.
  • Run the PS command: Add-Migration -MySecondMigration Name -StartUpProjectName MyApp.Web -ProjectName MyApp.Migrations -ConfigurationTypeName "MyApp.Migrations.MyMigrationConfiguration" -ConnectionString "Data Source =. \ SQLEXPRESS; Database = False = Demo = false ID = x; Password = x "-ConnectionProviderName" System.Data.SqlClient "- Boom.
  • Subtlety - The Migrator does not even connect to MSSQL to check if db exists or if there is a dbo .__ MigrationHistory! I went ahead and disabled the MSSQL service! - It doesn’t matter if I enter the db false name or not, or I disconnect the entire MSSQL server - the error is the same and the connection is not made. So, how does he know that migration is pending when it does not check the database? I assume a mistake.
  • I have __dbo.MigrationHistory created already with the initial migration in it.
  • Error. It is not possible to create an explicit migration because the following explicit migrations are expected: [201402121953301_Initial]. Apply pending explicit migrations before attempting to generate a new explicit migration.

Here is my configuration - nothing special:

public class MyMigrationConfiguration : DbMigrationsConfiguration<MyMigrationContext> { public MyMigrationConfiguration() { AutomaticMigrationsEnabled = false; AutomaticMigrationDataLossAllowed = false; MigrationsNamespace = "---"; MigrationsDirectory = "---"; } } 

Here is the method with which I create dbs:

  public void CreateOrUpdateDb(string DbName) { try { string connectionString = _connectionStringProvider.GetConnectionString(DbName); DbMigrationsConfiguration cfg = CreateMigrationsConfig(connectionString); cfg.AutomaticMigrationsEnabled = false; cfg.AutomaticMigrationDataLossAllowed = false; DbMigrator dbMigrator = new DbMigrator(cfg); dbMigrator.Update(); } catch (MigrationsException exception) { _logger.Error(string.Format("Error creating database '{0}'",DbName), exception); } } 

I have already searched and read everything that I can find on the Internet, but most examples include the Configuration.cs standard, etc. No one explains why I need to run Enable-Migrations because it creates Configuration.cs, but I myself provide the Configuration class and do not need this other class.

Here is the exception stack:

 > System.Data.Entity.Migrations.Infrastructure.MigrationsPendingException: Unable to generate an explicit migration because the following explicit migrations are pending: [201402121953301_Initial]. Apply the pending explicit migrations before attempting to generate a new explicit migration. at System.Data.Entity.Migrations.DbMigrator.Scaffold(String migrationName, String namespace, Boolean ignoreChanges) at System.Data.Entity.Migrations.Design.MigrationScaffolder.Scaffold(String migrationName, Boolean ignoreChanges) at System.Data.Entity.Migrations.Design.ToolingFacade.ScaffoldRunner.Scaffold(MigrationScaffolder scaffolder) at System.Data.Entity.Migrations.Design.ToolingFacade.ScaffoldRunner.Run() at System.AppDomain.DoCallBack(CrossAppDomainDelegate callBackDelegate) at System.AppDomain.DoCallBack(CrossAppDomainDelegate callBackDelegate) at System.Data.Entity.Migrations.Design.ToolingFacade.Run(BaseRunner runner) at System.Data.Entity.Migrations.Design.ToolingFacade.Scaffold(String migrationName, String language, String rootNamespace, Boolean ignoreChanges) at System.Data.Entity.Migrations.AddMigrationCommand.Execute(String name, Boolean force, Boolean ignoreChanges) at System.Data.Entity.Migrations.AddMigrationCommand.<>c__DisplayClass2.<.ctor>b__0() 

Is there a way to get migrants to make a script without telling me that there are some pending migrations, although they are not? This is a 100% error in EF, but I do not know how to get around this.

+1
source share
1 answer

We found the answer - smart my colleague and using Reflector.

  • Inside EntityFramework.dll there is a class
  • System.Data.Entity.Migrations.DbMigrator using the method
  • Scaffold (line migName, line @namespace, bool ignoreChanges)
  • It makes a call to this.GetPendingMigrations
  • Which method calls another method in another class HistoryRepository.CreateHistoryQuery (context HistoryContext, string contextKey = null) with parameter contextKey == NULL
  • But inside this method it happens

    contextKey =! string.IsNullOrWhiteSpace (contextKey)? contextKey.RestrictTo (this._contextKeyMaxLength): this._contextKey;

and contextKey is no longer zero. IT actually becomes a type (YourInheritedDbMigrationConfiguration) .ToString ()

Where is the problem? The problem is

  • I use two different DbMigrationConfiguration classes
  • since the migration assembly is separate from the application core, which makes
  • their two different "fully qualified named classes" which at the end
  • lead to two different ContextKeys in the dbo._MigrationHistory table for the DbMigrationConfiguration, which is used to generate the migration script.

So, when I do the initial migration of the script and start the site, and the site applies the script, this is fine, but the dbo._MigrationHistory ContextKey is "MyDbConigClass1". After that, when I run Add-Migration, which uses a different DbMigrationConfiguration class, ContextKeys does not match - BOOM!

Solution : the same ContextKey = "MyTenantDb" was added in both of my configuration classes, and everything started working again because the type names are no longer involved, but DbMigrator used my custom ContextKey :)

+3
source

Source: https://habr.com/ru/post/1209101/


All Articles