Unable to enable migration in Entity Framework 4.3

I have a class library with EF Code First. I just upgraded to EF 4.3 and now I want to enable migrations.

I type Enable-Migrations -ProjectName MyProjectName in the PM console, but I get the following error

 PM> Enable-Migrations -ProjectName MyProjectName System.Collections.Generic.KeyNotFoundException: The given key was not present in the dictionary. at System.Collections.Generic.Dictionary`2.get_Item(TKey key) at System.Data.Entity.Migrations.DbMigrationsConfiguration.GetSqlGenerator(String providerInvariantName) at System.Data.Entity.Migrations.DbMigrator..ctor(DbMigrationsConfiguration configuration, DbContext usersContext) at System.Data.Entity.Migrations.DbMigrator..ctor(DbMigrationsConfiguration configuration) at System.Data.Entity.Migrations.Design.MigrationScaffolder..ctor(DbMigrationsConfiguration migrationsConfiguration) at System.Data.Entity.Migrations.Design.ToolingFacade.ScaffoldRunner.RunCore() at System.Data.Entity.Migrations.Design.ToolingFacade.BaseRunner.Run() The given key was not present in the dictionary. PM> 

I can’t determine which dictionary might be wrong.

My connection string looks like this:

 <connectionStrings> <add name="MySystem" connectionString="Data Source=MyServer\Instance;Initial Catalog=myDbName;Integrated Security=True" providerName="System.Data.SqlClient" /> </connectionStrings> 

Any idea on what might be wrong?

Just notice:
I use my class library in a console application with an exact copy of my app.config and there I can access my database perfectly.

+4
source share
3 answers

It turned out that Anders Abel was right in this matter, but we found a much simpler solution.

The mvc-mini-profiler page has a special package in Nuget called MiniProfiler.EF that does not require any wrapping around SqlConnection . We dropped our old mvc mini profiler and installed MiniProfiler.EF . Then Enable-Migrations worked as expected.

+4
source

EF Code First has an extensible provider model for generating Sql code. The documentation for DbMigrationsConfiguration.GetSqlGenerator says what it does:

Gets the SQL generator that is configured for use with this provider database.

MvcMiniProfiler wraps around a database provider to add profiling support. For EF, it will look like you are using MvcMiniProfiler DB, not MSSQL DB. Unfortunately, EF Code does not know how to handle the MvcMiniProfiler DB.

A possible solution would be to add a SqlGenerator named MvcMiniProfiler, which wraps the Sql server generator.

Edit

It seems that one could simply re-register the existing SQL server generator for the mvc mini profiler name (if you select its name).

At http://romiller.com/2012/01/16/customizing-code-first-migrations-provider/ there is a code snippet that shows how to register a provider:

 public Configuration() { AutomaticMigrationsEnabled = false; SetSqlGenerator("System.Data.SqlClient", new CustomMigrationsProviders.CustomSqlServerMigrationSqlGenerator()); } 
+3
source

It may be related, but another problem, but since it was Anders' message that led me to a solution, I thought that I also post this solution.

Problem:

If the MiniProfiler is initialized before the Entity Framework database initialization strategies are executed, the initialization will fail with a missing migration table.

If the initialization strategies of the Entity Framework database are executed, access to the objects fails with the exception of a type exception, because MiniProfiler DbConnection tries to force the SqlConnection into the variable (in the internal generic format).

Cause:

When the MiniProfiler is initialized, it uses reflection to retrieve the collection of database providers from the private static field in System.Data.Common.DbProviderFactories. He then rewrites this list using the MiniProfiler firmware providers to replace local providers. This allows MiniProfiler to easily intercept any calls to the database.

When the Entity Framework initializes, it starts compiling data models and creating cached initialized databases stored in System.Data.Entity.Internal.LazyInternalContext inside some private static fields. After they are created, queries to DbContext use cached models and databases that are internally typed to use the providers that existed during initialization.

When the Entity Framework database initialization strategy is launched, it needs access to its first Sql provider, not MiniProfiler, to properly create SQL to create tables. But once these calls for the native provider are made, the native provider is cached in the LazyInternalContext, and we can no longer enter MiniProfiler pads without crashing at runtime.

My decision:

Access private collections inside System.Data.Entity.Internal.LazyInternalContext and flush cached compiled models and initialized databases.

If I perform this cleanup between the actions of the EF database initialization strategies and the MiniProfiler initialization, then it will be possible to insert MiniProfiler gaskets without a subsequent malfunction.

Code: This code helped:

 Type type = typeof(DbContext).Assembly.GetType("System.Data.Entity.Internal.LazyInternalContext"); object concurrentDictionary = (type.GetField("InitializedDatabases", BindingFlags.NonPublic | BindingFlags.Static)).GetValue(null); var initializedDatabaseCache = (IDictionary)concurrentDictionary; if (initializedDatabaseCache != null) initializedDatabaseCache.Clear(); object concurrentDictionary2 = (type.GetField("CachedModels", BindingFlags.NonPublic | BindingFlags.Static)).GetValue(null); var modelsCache = (IDictionary)concurrentDictionary2; if (modelsCache != null) modelsCache.Clear(); 

Attention:

It looks like the internal field names in LazyInternalContext change between versions of EF, so you might need to change this code to work with the exact version of EF that you included in your project.

0
source

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


All Articles