Не удается включить миграцию в Entity Framework 4.3 - PullRequest
4 голосов
/ 08 марта 2012

У меня есть библиотека классов с EF Code First. Я только что обновился до EF 4.3 и теперь хочу включить миграцию.

Я набираю Enable-Migrations -ProjectName MyProjectName в консоли PM, но получаю следующую ошибку

PM> Enable-Migrations -ProjectName MyProjectName
System.Collections.Generic.KeyNotFoundException: The given key was not present in the dictionary.
   at System.Collections.Generic.Dictionary`2.get_Item(TKey key)
   at System.Data.Entity.Migrations.DbMigrationsConfiguration.GetSqlGenerator(String providerInvariantName)
   at System.Data.Entity.Migrations.DbMigrator..ctor(DbMigrationsConfiguration configuration, DbContext usersContext)
   at System.Data.Entity.Migrations.DbMigrator..ctor(DbMigrationsConfiguration configuration)
   at System.Data.Entity.Migrations.Design.MigrationScaffolder..ctor(DbMigrationsConfiguration migrationsConfiguration)
   at System.Data.Entity.Migrations.Design.ToolingFacade.ScaffoldRunner.RunCore()
   at System.Data.Entity.Migrations.Design.ToolingFacade.BaseRunner.Run()
The given key was not present in the dictionary.
PM> 

Я не могу понять, какой словарь может быть неправильным.

Моя строка подключения выглядит следующим образом:

<connectionStrings>
  <add name="MySystem" connectionString="Data Source=MyServer\Instance;Initial Catalog=myDbName;Integrated Security=True" providerName="System.Data.SqlClient" />
</connectionStrings>

Есть идеи о том, что может быть не так?

Просто примечание:
Я использую свою библиотеку классов в консольном приложении с точной копией моего app.config, и там я могу получить отличный доступ к своей базе данных.

Ответы [ 3 ]

4 голосов
/ 09 марта 2012

Оказалось, что Андерс Абель был прав, но мы нашли гораздо более простое решение.

Согласно странице mvc-mini-profiler в Nuget есть специальный пакетназывается MiniProfiler.EF, который не требует никакой оболочки вокруг SqlConnection.Мы уронили наш старый mvc-mini-profiler и установили MiniProfiler.EF.Тогда Enable-Migrations работал как положено.

3 голосов
/ 08 марта 2012

EF Code First имеет расширяемую модель провайдера для генерации кода Sql. Документация для DbMigrationsConfiguration.GetSqlGenerator говорит, что он делает:

Получает генератор SQL, который настроен для использования с данной базой данных. провайдер.

MvcMiniProfiler оборачивается вокруг провайдера БД, чтобы добавить поддержку профилирования. Для EF это будет выглядеть так, как будто вы используете MvcMiniProfiler DB, а не MSSQL DB. К сожалению, EF Code сначала не знает, как обращаться с БД MvcMiniProfiler.

Возможное исправление заключается в добавлении SqlGenerator с именем MvcMiniProfiler, которое оборачивает генератор Sql Server.

Редактировать

Похоже, что можно просто перерегистрировать существующий генератор sql-сервера для имени мини-профилировщика mvc (если вы выясните его имя).

В http://romiller.com/2012/01/16/customizing-code-first-migrations-provider/ есть фрагмент кода, который показывает, как зарегистрировать провайдера:

public Configuration()
{
    AutomaticMigrationsEnabled = false;

    SetSqlGenerator("System.Data.SqlClient", 
        new CustomMigrationsProviders.CustomSqlServerMigrationSqlGenerator());
}
0 голосов
/ 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, которую вы включили в свой проект..

...