使用Mini-Profilier和EF 4.3& MVC 4没有创建数据库

时间:2012-03-02 20:32:33

标签: c# asp.net-mvc entity-framework mvc-mini-profiler

我遇到的问题是我们对现有数据库使用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)

4 个答案:

答案 0 :(得分:27)

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

  • EntityFramework
  • MiniProfiler
  • MiniProfiler.EF

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

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

    public IDbSet<Employee> Employees { get; set; } 
}

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

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

答案 1 :(得分:1)

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

可能的情况:

  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();
    
  4. 使用mvc4,Ef 4.3测试现有数据库。

答案 2 :(得分:1)

问题:

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

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

原因:

当MiniProfiler初始化时,它使用反射从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的确切版本。

答案 3 :(得分:0)

我发现了禁用EntityFramework数据库初始化的额外“黑客”问题(如果不需要)。 在初始化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

的问题