【问题标题】:Using Mini-Profilier with EF 4.3 & MVC 4 without creating the database将 Mini-Profilier 与 EF 4.3 和 MVC 4 一起使用而不创建数据库
【发布时间】:2012-03-02 20:32:32
【问题描述】:

我有一个问题,我们针对现有数据库使用 EF 4.3 Code First。我想将 Mini-Profiler 与 EF 一起使用并调用

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 Mini Profiler?我在测试中使用了 1.9 并且它有效。这些错误似乎与探查器无关。您使用什么代码关闭 Code First 中导致 Code First 查看这些表的约定?
  • 我也在使用 1.9。当我不使用分析器时,我得到的数据很好,没有崩溃。
  • 您使用了哪些代码来关闭 Code First 中导致 Code First 查看这些表的约定?一旦正确配置 Code First 以处理现有数据库,则根本不应查询这些表。

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


【解决方案1】:

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

  • 实体框架
  • 迷你分析器
  • 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 表的查询根本不应该发生。

【讨论】:

  • 我正在使用 MVC 4 和 EF 4.3,我在标题中提到...不是 MVC 3。
  • 我认为 MVC 版本与此无关,但我会检查一下。
  • 太棒了,这确实有效!我只是错过了那个静态方法调用!谢谢!
  • 很好,静态构造函数还解决了我在控制台应用程序尝试连接到 EF 代码优先上下文时遇到的问题
  • 这仅适用于使用分析器吗? (我在 HibernatingRhino 的分析器中遇到了类似的问题)。这是你只想在开发代码中做的事情吗?即有没有副作用?
【解决方案2】:

当我错过 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();
    

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

【讨论】:

  • 不,这并没有解决问题。我已经在代码中拥有了所有这些。这是 Code First 永远不会生成并且永远不会生成的数据库。因此,这两个表在这个数据库中不存在。
【解决方案3】:

问题:

如果 MiniProfiler 在我们的 Entity Framework 数据库初始化策略执行之前被初始化,那么初始化会失败并出现关于缺少迁移表的错误。

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

原因:

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

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

当 Entity Framework 数据库初始化策略运行时,它需要访问裸机的原生 Sql 提供程序,而不是 MiniProfiler shim,以便正确生成 SQL 以创建表。但是一旦对原生提供者进行了这些调用,原生提供者就会被缓存到 LazyInternalContext 中,我们不能再注入 MiniProfiler shims 而不会出现运行时故障。

我的解决方案:

访问 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。

【讨论】:

    【解决方案4】:

    我发现禁用 EntityFramework 数据库初始化(如果不需要)的其他“黑客”问题。 在初始化 db 上下文和 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 表的问题

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-06-05
      • 1970-01-01
      • 2011-10-01
      • 2012-04-21
      相关资源
      最近更新 更多