Entity framework Can';t在实体框架4.3中启用迁移

Entity framework Can';t在实体框架4.3中启用迁移,entity-framework,entity-framework-migrations,entity-framework-4.3,Entity Framework,Entity Framework Migrations,Entity Framework 4.3,我有一个带有EF代码的类库。我刚刚升级到EF 4.3,现在我想启用迁移 我在PM控制台中键入启用迁移-ProjectName MyProjectName,但收到以下错误 PM> Enable-Migrations -ProjectName MyProjectName System.Collections.Generic.KeyNotFoundException: The given key was not present in the dictionary. at System.Co

我有一个带有EF代码的类库。我刚刚升级到EF 4.3,现在我想启用迁移

我在PM控制台中键入
启用迁移-ProjectName MyProjectName
,但收到以下错误

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> 
我想不出哪本字典可能错了

我的连接字符串如下所示:

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

你知道有什么不对吗

请注意:

我在控制台应用程序中使用类库和app.config的精确副本,在那里我可以很好地访问我的数据库。

EF Code首先有一个用于Sql代码生成的可扩展提供程序模型。
DbMigrationsConfiguration.GetSqlGenerator
的文档说明了它的功能:

获取设置为与给定数据库一起使用的SQL生成器 提供者

MvcMiniProfiler将自己包装在DB提供程序周围,以添加分析支持。要执行EF,看起来您使用的是MvcMiniProfiler数据库,而不是MSSQL数据库。不幸的是,EF代码首先不知道如何处理MvcMiniProfiler数据库

一个可能的修复方法是添加一个具有MvcMiniProfiler名称的SqlGenerator,该名称包装Sql Server生成器

编辑 看起来可以为mvc迷你探查器名称重新注册现有的sql server生成器(如果您知道它的名称的话)

在,有一段代码片段显示了如何注册提供程序:

public Configuration()
{
    AutomaticMigrationsEnabled = false;

    SetSqlGenerator("System.Data.SqlClient", 
        new CustomMigrationsProviders.CustomSqlServerMigrationSqlGenerator());
}

事实证明安德斯·亚伯的原因是正确的,但我们找到了一个简单得多的解决办法


据介绍,Nuget中有一个名为
MiniProfiler.EF
的特殊包,它不需要
SqlConnection
的任何包装。我们放弃了旧的mvc迷你探查器,安装了
MiniProfiler.EF
。然后,
启用迁移
按预期工作。

这可能是一个相关但不同的问题,但由于是Anders在这里的帖子引导我找到了解决方案,我想我也在这里发布了这个解决方案

问题:

如果在执行实体框架数据库初始化策略之前初始化了MiniProfiler,则初始化会失败,并出现一个关于缺少迁移表的错误

如果首先执行Entity Framework数据库初始化策略,则对实体的访问将失败,并出现类型转换异常,因为MiniProfiler DbConnection试图强制进入SqlConnection变量(在内部泛型中)

原因:

当MiniProfiler初始化时,它使用反射从System.Data.Common.DbProviderFactorys中的私有静态字段检索数据库提供程序的集合。然后,它使用MiniProfiler垫片提供程序重写此列表,以替换本机提供程序。这允许MiniProfiler以静默方式拦截对数据库的任何调用

当实体框架初始化时,它开始编译数据模型,并在一些私有静态字段中创建存储在System.data.Entity.Internal.LazyInternalContext中的缓存初始化数据库。一旦创建了这些,针对DbContext的查询将使用缓存的模型和数据库,这些模型和数据库在内部类型化,以使用初始化时存在的提供程序

当实体框架数据库初始化策略运行时,它需要访问原始Sql提供程序,而不是MiniProfiler垫片,以便正确生成Sql以创建表。但是,一旦对本机提供程序进行了这些调用,本机提供程序就会被缓存到LazyInternalContext中,如果没有运行时故障,我们就无法再注入MiniProfiler

我的解决方案:

访问System.Data.Entity.Internal.LazyInternalContext中的私有集合,并清除缓存的编译模型和初始化的数据库

如果我在EF数据库初始化策略的操作和MiniProfiler的初始化之间执行此清除,则可以插入MiniProfiler垫片,而不会导致以后的运行时故障

代码: 这段代码帮了我的忙:

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();
警告:


LazyInternalContext中的内部字段的名称在EF的不同版本之间可能会发生变化,因此您可能需要修改此代码以使用项目中包含的EF的确切版本。

看起来MvcMiniProfiler可能是罪魁祸首。删除它可以启用迁移。