在不创建数据库的情况下,将Mini-Profilier与EF 4.3和MVC 4配合使用

我有一个问题,我们在现有数据库中使用EF 4.3 Code First。 我想使用带有EF的Mini-Profiler并打电话

MvcMiniProfiler.MiniProfilerEF.Initialize(); 

但是,由于我们实际上并未创建任何表,因此dbo .__ MigrationHistory和dbo.EdmMetadata表不存在。 分析器最终崩溃,因为它们不存在。 有没有办法让探查器忽略这些EF Code First特定的表? 谢谢!

编辑:

这些是我得到的例外:(它们分开来)

 Invalid object name 'dbo.__MigrationHistory'. at System.Data.SqlClient.SqlConnection.OnError(SqlException exception, Boolean breakConnection) at System.Data.SqlClient.SqlInternalConnection.OnError(SqlException exception, Boolean breakConnection) at System.Data.SqlClient.TdsParser.ThrowExceptionAndWarning() at System.Data.SqlClient.TdsParser.Run(RunBehavior runBehavior, SqlCommand cmdHandler, SqlDataReader dataStream, BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject stateObj) at System.Data.SqlClient.SqlDataReader.ConsumeMetaData() at System.Data.SqlClient.SqlDataReader.get_MetaData() at System.Data.SqlClient.SqlCommand.FinishExecuteReader(SqlDataReader ds, RunBehavior runBehavior, String resetOptionsString) at System.Data.SqlClient.SqlCommand.RunExecuteReaderTds(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, Boolean async) at System.Data.SqlClient.SqlCommand.RunExecuteReader(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, String method, DbAsyncResult result) at System.Data.SqlClient.SqlCommand.RunExecuteReader(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, String method) at System.Data.SqlClient.SqlCommand.ExecuteReader(CommandBehavior behavior, String method) at System.Data.SqlClient.SqlCommand.ExecuteDbDataReader(CommandBehavior behavior) at System.Data.Common.DbCommand.ExecuteReader(CommandBehavior behavior) at MvcMiniProfiler.Data.ProfiledDbCommand.ExecuteDbDataReader(CommandBehavior behavior) in \mvc-mini-profiler\MvcMiniProfiler\Data\ProfiledDbCommand.cs:line 155 at System.Data.Common.DbCommand.ExecuteReader(CommandBehavior behavior) at System.Data.EntityClient.EntityCommandDefinition.ExecuteStoreCommands(EntityCommand entityCommand, CommandBehavior behavior) Invalid object name 'dbo.EdmMetadata'. at System.Data.SqlClient.SqlConnection.OnError(SqlException exception, Boolean breakConnection) at System.Data.SqlClient.SqlInternalConnection.OnError(SqlException exception, Boolean breakConnection) at System.Data.SqlClient.TdsParser.ThrowExceptionAndWarning() at System.Data.SqlClient.TdsParser.Run(RunBehavior runBehavior, SqlCommand cmdHandler, SqlDataReader dataStream, BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject stateObj) at System.Data.SqlClient.SqlDataReader.ConsumeMetaData() at System.Data.SqlClient.SqlDataReader.get_MetaData() at System.Data.SqlClient.SqlCommand.FinishExecuteReader(SqlDataReader ds, RunBehavior runBehavior, String resetOptionsString) at System.Data.SqlClient.SqlCommand.RunExecuteReaderTds(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, Boolean async) at System.Data.SqlClient.SqlCommand.RunExecuteReader(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, String method, DbAsyncResult result) at System.Data.SqlClient.SqlCommand.RunExecuteReader(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, String method) at System.Data.SqlClient.SqlCommand.ExecuteReader(CommandBehavior behavior, String method) at System.Data.SqlClient.SqlCommand.ExecuteDbDataReader(CommandBehavior behavior) at System.Data.Common.DbCommand.ExecuteReader(CommandBehavior behavior) at MvcMiniProfiler.Data.ProfiledDbCommand.ExecuteDbDataReader(CommandBehavior behavior) in \mvc-mini-profiler\MvcMiniProfiler\Data\ProfiledDbCommand.cs:line 155 at System.Data.Common.DbCommand.ExecuteReader(CommandBehavior behavior) at System.Data.EntityClient.EntityCommandDefinition.ExecuteStoreCommands(EntityCommand entityCommand, CommandBehavior behavior) 

我启动了一个新的MVC 4项目并安装/更新了以下NuGet包:

  • 的EntityFramework
  • MiniProfiler
  • MiniProfiler.EF

我在我的数据库上下文中的Code First中关闭了数据库初始化策略。

 public class EmployeeContext : DbContext { static EmployeeContext() { Database.SetInitializer( null ); // must be turned off before mini profiler runs } public IDbSet Employees { get; set; } } 

迷你探测器工作正常。 我手动创建了一个表数据库。

在静态构造函数中关闭数据库初始值设定项非常重要。 如果您在其他地方执行此操作,那么迷你探查器代码可能会在您的代码之前运行,因此对__MigrationHistory表的查询可能根本不会发生。

当我错过miniprofiler的设置时,会发生此exception。

可能的情况:

  1. 缺少包含在您的布局标题中

    @ MvcMiniProfiler.MiniProfiler.RenderIncludes()

  2. 缺少App_Start文件夹中的“MiniProfiler.cs”。

  3. 在Application_Start()函数中缺少调用

     AreaRegistration.RegisterAllAreas(); RegisterGlobalFilters(GlobalFilters.Filters); RegisterRoutes(RouteTable.Routes); BundleTable.Bundles.RegisterTemplateBundles(); MiniProfilerEF.Initialize(); 

对于现有数据库,使用mvc4,Ef 4.3进行测试。

问题:

如果在执行Entity Framework数据库初始化策略之前初始化MiniProfiler,则初始化将失败,并显示有关缺少迁移表的错误。

如果entity framework数据库初始化策略首先执行,则对实体的访问会因类型转换exception而失败,因为尝试将MiniProfiler DbConnection强制转换为SqlConnection变量(在内部通用中)。

原因:

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

当Entity Framework初始化时,它开始编译数据模型并在一些私有静态字段内创建存储在System.Data.Entity.Internal.LazyInternalContext中的缓存初始化数据库。 创建这些后,对DbContext的查询将使用内部键入的缓存模型和数据库来使用在初始化时存在的提供程序。

当Entity Framework数据库初始化策略运行时,它需要访问裸的本机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的确切版本。

我发现了禁用EntityFramework数据库初始化的额外“hack”问题(如果不需要)。 在初始化db contexts和MiniProfiler之前,应将DB的DefaultInitializer设置为null

 Type type = typeof(DbContext).Assembly.GetType("System.Data.Entity.Internal.LazyInternalContext"); var field = type.GetField("DefaultCodeFirstInitializer", BindingFlags.NonPublic | BindingFlags.Static); if (field != null) field.SetValue(null, null); else { var field2 = type.GetField("_defaultCodeFirstInitializer", BindingFlags.NonPublic | BindingFlags.Static); if (field2 != null) field2.SetValue(null, null); } 

因此,它将解决dbo.EdmMetadatadbo.__MigrationHistory表的问题