Миграции Entity Framework: всегда вызывается конструктор конфигурации

Я создал простое консольное приложение, установил EntityFramework из nuget и выполнил команду Enable-Migrations.

Вот код основного:

using(var ctx = new AppDbContext())
{
   var persons = ctx.Persons.ToList();
   Console.ReadKey();
}

Вот код класса Configuration

internal sealed class Configuration : DbMigrationsConfiguration<AppDbContext>
{
    public Configuration()
    {
        AutomaticMigrationsEnabled = true;
        Console.WriteLine("Configuration: Constructor");
    }

    protected override void Seed(AppDbContext context)
    {
        Console.WriteLine("Configuration: Seed");
    }
}

Вот часть структуры сущности в app.config:

<entityFramework>
  <defaultConnectionFactory type="System.Data.Entity.Infrastructure.LocalDbConnectionFactory, EntityFramework">
    <parameters>
      <parameter value="mssqllocaldb" />
    </parameters>
  </defaultConnectionFactory>
  <providers>
    <provider invariantName="System.Data.SqlClient" type="System.Data.Entity.SqlServer.SqlProviderServices, EntityFramework.SqlServer" />
  </providers>
</entityFramework>

Если я запускаю консольное приложение, то выполняется конструктор класса Configuration для миграции. Почему? Я не меняю инициализатор базы данных.

Обновлять

Теперь я попробовал некоторые инициализаторы базы данных и посмотрел, вызывается ли конструктор класса конфигурации. Вот мой результат:

public class AppDbContext : DbContext
{
    static AppDbContext()
    {
        //Database.SetInitializer<AppDbContext>(new CreateDatabaseIfNotExists<AppDbContext>());
        // ==> Configuration class constructor called

        //Database.SetInitializer<AppDbContext>(new DropCreateDatabaseIfModelChanges<AppDbContext>());
        // ==> Configuration class constructor called

        //Database.SetInitializer<AppDbContext>(new DropCreateDatabaseAlways<AppDbContext>());
        // ==> Configuration class constructor called

        Database.SetInitializer<AppDbContext>(null);
        // ==> Configuration class constructor is NOT called
    }

    public IDbSet<Person> Persons { get; set; }
}

Я явно задаю инициализатор базы данных, но вызывается конструктор класса Configuration. Странное поведение.


person malt    schedule 03.06.2015    source источник
comment
У вас включена автоматическая миграция? Вы получаете сообщение об ошибке? Возможно, потребуется увидеть ваш класс контекста.   -  person Steve Greene    schedule 03.06.2015
comment
Итак, вы говорите, что нигде не используете Database.SetInitializers?   -  person Ruskin    schedule 04.06.2015
comment
Да, я не устанавливаю инициализатор базы данных, ни в app.config, ни в коде.   -  person malt    schedule 04.06.2015


Ответы (1)


Как вы упомянули, вы выполнили команду Enable-Migrations. Так что же делает добавление нового класса конфигурации Migration. Этот класс будет применять изменения конфигурации, указанные в классе, связанные с миграциями, когда вы запускаете приложение.

DatabaseInitializers — это стратегии для применения миграций, даже если вы их не коснулись, но объект класса Configuration будет создан.

Обновлять:

Если вы не делаете этого в своем коде, посмотрите файл конфигурации вашего приложения. Это может иметь что-то вроде:

    <contexts>
      <context type="AppDbContext, MyAssembly">
        <databaseInitializer 
type="System.Data.Entity.MigrateDatabaseToLatestVersion`2[[AppDbContext, MyAssembly], 
                             [Migrations.Configuration, MyAssembly]], EntityFramework" />  


</context>

Дополнительные сведения см. в этой документации.

Обновление 2:

Думаю, я нашел ответ. При просмотре кода EntityFramework ясно видно, что databaseInitializer запускается, когда реализуется ваш первый запрос linq. См. приведенный ниже стек вызовов, полученный во время отладки приложения.

Скриншот стека вызовов из конструктора конфигурации

Случай 1: когда вы используете Database.SetInitializer<AppDbContext>(null);, который фактически создает NullDatabaseInitializer<TContext>() в качестве инициализатора по умолчанию, который ничего не делает, поэтому конфигурация не вызывалась.

Вариант 2: когда вы удаляете строку Database.SetInitializer<AppDbContext>(null);, все начинает использовать значения поставщиков по умолчанию. В этом случае внешняя спецификация DatabaseInitializer не предоставляется, поэтому EF получит инициализатор по умолчанию, который в данном случае равен CreateIfNotExist<AppDbContext>. Затем инициализатор попытается найти конфигурацию, и, конечно же, у него есть класс конфигурации, поэтому будет создан экземпляр класса конфигурации и будет вызван конструктор.

Хотя мне потребовалось пару часов, чтобы понять это.

person vendettamit    schedule 03.06.2015
comment
Я не менял инициализатор базы данных, поэтому MigrateDatabaseToLatestVersion‹..› не используется. Но конструктор класса Configuration выполняется, но я не понимаю, зачем этот конструктор вызывается. Почему это необходимо? Если я добавлю второй класс Configuration2, то конструкторы Configuration и Configuration2 не будут выполняться. Что это за логика? - person malt; 04.06.2015
comment
Смотрите мой обновленный ответ. Я добавил подробности о том, что еще может быть ответственным за создание экземпляра конфигурации миграции. - person vendettamit; 04.06.2015
comment
Спасибо, но я не меняю файл конфигурации. Я не устанавливаю инициализатор через файл конфигурации. Я пробовал сейчас много разных инициализаторов. Смотрите исходный пост с результатами... Очень интересно. - person malt; 04.06.2015
comment
Можете ли вы поделиться образцом кода, где его можно воспроизвести? Я бы очень хотел посмотреть, что там происходит. - person vendettamit; 04.06.2015
comment
Это действительно странное поведение. Здесь вы можете скачать код dl.dropboxusercontent.com/u/2856423/EfMigrationTest2.zip< /а> - person malt; 04.06.2015
comment
На моем конце он работает нормально, не переходя к конструктору конфигурации. - person vendettamit; 04.06.2015
comment
вы видите в коде, что я установил инициализатор базы данных на ноль. В этом случае конструктор класса Configuration не вызывается. Но если вы прокомментируете эту строку Database.SetInitializer‹AppDbContext›(null); затем вызывается конструктор класса Configuration, хотя используется инициализатор базы данных по умолчанию, а не инициализатор MigrateDatabaseToLatestVersion. - person malt; 04.06.2015
comment
@malt Я понял это .. Смотрите мой обновленный ответ. И я тоже узнал несколько новых вещей. ;) +1 за вопрос. - person vendettamit; 04.06.2015
comment
Да, я уже видел это, когда закончил публиковать ответ. Мне нравится идея иметь несколько классов конфигурации, о которых вы просили. - person vendettamit; 05.06.2015