Проблема:
Если 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, которую вы включили в свой проект..