Использование Mini-Profilier с EF 4.3 и MVC 4 без создания базы данных - PullRequest
24 голосов
/ 03 марта 2012

У меня проблема с использованием EF 4.3 Code First в отношении существующей базы данных. Я хочу использовать Mini-Profiler с EF и звонить

MvcMiniProfiler.MiniProfilerEF.Initialize();

Однако, поскольку мы фактически не создаем ни одной из таблиц, таблицы dbo .__ MigrationHistory и dbo.EdmMetadata не существуют. Профилировщик заканчивается сбоем, потому что они не существуют. Есть ли способ заставить профилировщик игнорировать эти специфические таблицы EF Code First? Спасибо!

EDIT:

Вот исключения, которые я получаю: (Они приходят отдельно)

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 ]

27 голосов
/ 19 марта 2012

Я запустил новый проект 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 голос
/ 18 апреля 2013

Проблема:

Если MiniProfiler инициализируется до выполнения наших стратегий инициализации базы данных Entity Framework, инициализация завершается с ошибкой об отсутствующей таблице миграции.

Еслистратегии инициализации базы данных Entity Framework выполняются первыми, доступ к объектам завершается неудачно с исключением типа приведения типа, поскольку попытка принудительного принудительного принудительного ввода MiniProfiler DbConnection в переменную SqlConnection (во внутреннем универсальном).

Причина:

Когда инициализируется MiniProfiler, он использует отражение для извлечения коллекции поставщиков баз данных из частного статического поля в System.Data.Common.DbProviderFactories.Затем он переписывает этот список с поставщиками прокладок MiniProfiler для замены собственных поставщиков.Это позволяет MiniProfiler перехватывать любые вызовы базы данных в режиме без вывода сообщений.

Когда инициализируется Entity Framework, он начинает компилировать модели данных и создавать кэшированные инициализированные базы данных, хранящиеся в System.Data.Entity.Internal.LazyInternalContext внутри некоторой частной статической структуры.поля.Как только они созданы, запросы к DbContext используют кэшированные модели и базы данных, которые внутренне типизированы для использования поставщиков, которые существовали во время инициализации.

Когда запускается стратегия инициализации базы данных Entity Framework, ему требуется доступ к голой, родной Sql-провайдер, а не Shim 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, которую вы включили в свой проект..

1 голос
/ 17 марта 2012

Это исключение возникает для меня, когда я пропускаю настройку для минипрофиля.

Возможные случаи:

  1. Отсутствует включение в тег заголовка макета

    @ MvcMiniProfiler.MiniProfiler.RenderIncludes ()

  2. Отсутствует "MiniProfiler.cs" в папке App_Start.

  3. Отсутствует вызов в функции Application_Start ()

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

Протестировано с mvc4, Ef 4.3 для существующей базы данных.

0 голосов
/ 11 июня 2013

Я обнаружил дополнительную проблему с "взломом" для отключения инициализации базы данных EntityFramework (если не требуется).DefaultInitializer для БД должен быть установлен в null перед инициализацией контекстов БД и MiniProfiler

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.EdmMetadata и dbo.__MigrationHistory

...