Почему для шага добавления-миграции EF Migrations в Entity Framework требуется строка подключения к базе данных?

Я пытаюсь использовать и понимать миграции EF (используя EF 4.3.1, Code First). Чтобы создать новое изменение, я должен использовать такую ​​​​команду:

Add-Migration MyMigration
   -ConnectionString "Data Source=.;Initial Catalog=mydb;" 
   -ConnectionProviderName "System.Data.SqlClient"
   -StartUpProjectName MyWebsite 
   -ProjectName MyEF.Migrations

Почему для Add-Migration требуются данные строки подключения? Update-Database нужен, в этом есть смысл. Но разве у Add-Migration нет всего необходимого из DbContext и Configuration?

Это не просто праздное чудо, это очень сбивает с толку, чтобы дать ему базу данных, потому что у нас есть «мультитенантность», когда желаемая база данных является гибкой и может меняться от запроса к запросу, не говоря уже о статическом времени компиляции. Так что, если Add-Migration на самом деле ИСПОЛЬЗУЕТ эту базу данных для чего-либо, у нас есть проблема.

ОБНОВЛЕНИЕ. Мы отказались от EF Migrations и вместо этого используем Fluent Migrator и довольны. Это намного, намного быстрее, даже с учетом того, что некоторые вещи приходится писать дважды (один раз для объекта EF и один раз для миграции), и у него нет проблем, обсуждаемых в этом вопросе.


person Scott Stafford    schedule 29.05.2012    source источник


Ответы (4)


Add-Migration проверяет наличие базы данных и взаимодействует с __MigrationHistory таблицей. Как упомянул @Anders Abel, он используется для исследования ожидающих миграций, а также для выбора предыдущей модели, чтобы действительно найти, что изменилось - это особенно важно, если вы добавляете явную миграцию в решение, в котором включена автоматическая миграция.

person Ladislav Mrnka    schedule 29.05.2012
comment
Он должен иметь возможность получить модель для сравнения со свойством Target миграции в Designer.cs. - person Scott Stafford; 30.05.2012
comment
И я не хочу, чтобы он знал об ожидающих миграциях, потому что они специфичны для любого состояния, в котором находится один случайный db (и отличается от других, которые я или моя команда использую)... ;( Боюсь, я Я все больше разочаровываюсь в дизайне EF Migrations — кажется, что он пытается сделать слишком много. - person Scott Stafford; 30.05.2012
comment
Неважно, сколько у вас баз данных. При разработке каждый разработчик должен использовать его и подготовить миграцию на основе кода. Затем во время развертывания вы должны перевести все свои базы данных в одно и то же состояние. Обработка миграций в командной разработке сложна и требует внесения изменений в модель с миграциями как можно скорее с некоторым ручным слиянием, если два разработчика одновременно вносили изменения в модель. Миграции переполнены — они привносят новые вызовы в разработку. Если вам это не нравится, не используйте их и обрабатывайте обновление базы данных вручную. - person Ladislav Mrnka; 31.05.2012
comment
Я разместил аналогичный вопрос ... Для миграции на основе кода не имеет смысла требовать, чтобы база данных существовала или обновлялась! :( stackoverflow.com/questions/11204900/ - person Danny Tuppeny; 26.06.2012
comment
@Danny: Это имеет смысл, потому что база данных может содержать миграции, которых нет в вашем коде ... - person Ladislav Mrnka; 26.06.2012
comment
@LadislavMrnka Почему это важно? Если база данных не синхронизирована во время разработки, что с того? Мы пишем сценарии изменений, которые будут выполняться во время выполнения с помощью DbMigrator. 99,9999 % кода в EF Migrations допускают этот сценарий. - person Danny Tuppeny; 26.06.2012

Мне стало любопытно, когда я прочитал ваш вопрос, поэтому я запустил Sql Server Profiler, чтобы посмотреть, что происходит при запуске add-migration. Он действительно подключается к базе данных и обращается к БД для проверки таблицы __MigrationHistory.

Это также видно из сообщения об ошибке, возникающего при попытке создать вторую миграцию на основе кода без запуска первой:

Не удалось сгенерировать явную миграцию, так как ожидаются следующие явные миграции: [201205291928386_foo]. Примените ожидающие явные миграции, прежде чем пытаться создать новую явную миграцию.

Я думаю, что механизм миграции использует сериализованную модель из базы данных, чтобы вычислить, какие шаги миграции следует включить в новую миграцию.

Насколько я понимаю, база данных используется только как помощник для генерации кода. Пока все различные базы данных, которые вы используете, совместимы с моделью в коде, это не должно быть проблемой для вас.

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

Как указывает @Ladislav Mrnka, при смешивании миграции на основе кода и автоматической миграции требуется проверка базы данных. Когда вы формируете новую миграцию, она должна включать в себя все, что изменилось в вашей модели с момента последней миграции. Если вы используете автоматические миграции, они не отслеживаются в коде. При расчете изменений, которые следует включить в миграцию, в качестве базы используется последняя миграция. Единственный способ проверить это - база данных, поскольку может быть включена автоматическая миграция.

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

person Anders Abel    schedule 29.05.2012
comment
Если я установлю для AutomaticMigrationsEnabled значение false, как изменится этот анализ? (Я думаю, что мог бы жить в мире без автоматической миграции, если бы мне больше не нужно было указывать базы данных.) - person Scott Stafford; 30.05.2012
comment
К сожалению, я не думаю, что анализ изменится. EF не может узнать, всегда ли у вас была отключена автоматическая миграция или вы работали с ней до сих пор и просто отключили ее перед запуском. - person Anders Abel; 30.05.2012
comment
Должен быть какой-то способ рассказать об этом! Не имеет смысла полностью убивать возможность использовать миграции таким образом с абсолютно нулевой пользой :( - person Danny Tuppeny; 26.06.2012
comment
Я опубликовал нечто подобное: stackoverflow.com/questions/11204900/ - person Danny Tuppeny; 26.06.2012

Я смотрел это видео Роуэна Миллера в марте 2014 года: Миграции — под капотом

В видео Роуэн объясняет, что команда Add-Migration выполняет несколько шагов, которые включают компонент с именем EdmModelDiffer. EdmModelDiffer сравнивает текущую модель с предыдущей моделью из последней миграции (которая встроена в файл resx предыдущей миграции), а затем вычисляет необходимые изменения в базе данных.

Таким образом, компоненту EdmModelDiffer требуется подключение к базе данных.

Шаги, описанные в видео:

  1. Построить текущую модель из кода
  2. Получить предыдущую модель из последней миграции (хранится как снимок в файле resx)
  3. Рассчитать необходимые изменения базы данных (сделано EdmModelDiffer)
  4. Создан новый файл миграции

Теоретически можно предположить, что будет достаточно сравнить текущую модель с моделью последней миграции, чтобы сгенерировать новую миграцию. Но тем временем другие люди могли внести изменения в базу данных. Наверное поэтому и есть проверка по базе. Без этого результирующий файл миграции не должен быть правильным.


Посмотрите также второе видео под названием Миграции — команда Окружающая среда

person Martin    schedule 07.12.2015

ОП написал:

Но разве у Add-Migration нет всего необходимого из DbContext и Configuration?

Нет, как упоминалось здесь, часть кода конструктора для ручной миграции (то, что создано add-migration) содержит снимок схемы вашей базы данных.

Тем не менее, тот факт, что вы используете строку подключения и т. Д., Очень странный. EF обычно подразумевает это из вашего класса(ов) DbContext и Web.Config. В проекте, где у меня есть одна база данных и один DbContext, я создаю класс конфигурации и добавляю ручную миграцию с помощью:

add-migration

Мне не нужно передавать какие-либо другие аргументы командной строки. Это в EF 4.3.1 — возможно, вы использовали CTP или какую-то более старую версию или просто неправильно поняли документы?

Если у меня есть несколько БД или DbContexts, у меня есть несколько классов конфигурации, и я использую, например:

add-migration -conf Log

Который использует мой класс конфигурации и соответствующую строку подключения в Web.config, чтобы добавить ручную миграцию для этой базы данных/DbContext.

Вот более длинный пример кода простого DbContext, предназначенного для хранения журналов (отдельно от основного db):

namespace MyProj.Models.Log
{
    public class LogDb : DbContext
    {
        public DbSet<LogLine> LogLines { get; set; }
        public DbSet<LogTag> LogTags { get; set; }


        protected override void OnModelCreating(DbModelBuilder modelBuilder)
        {
            modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
        }
    }

    public LogDb()
#if DEPLOYDB
         : base("LogDeploy")
#else
         : base()
#endif
     {
     }
}

namespace MyProj.Migrations
{
    internal sealed class Log : DbMigrationsConfiguration<LogDb>
    {
        public Log()
        {
            AutomaticMigrationsEnabled = true;
        }
    }
}

В Web.Config:

<add name="LogDb" connectionString="Initial Catalog=Log;Data Source=.\SqlExpress;Integrated Security=SSPI;MultipleActiveResultSets=true" providerName="System.Data.SqlClient" />
<add name="LogDeploy" connectionString="Initial Catalog=Log;Data Source=00.00.000.00,12345;User ID=sql;Password=xxx;Network Library=DBMSSOCN" providerName="System.Data.SqlClient" />

Итак, в этом примере у меня есть несколько баз данных, несколько DbContexts. LogDb использует другую строку подключения в Web.Config в зависимости от того, определено ли "DBDEPLOY" во время компиляции; если это так, он использует «LogDeploy». Если нет, используется значение по умолчанию — строка подключения с тем же именем, что и у класса, «LogDb». Это позволяет мне легко развертывать изменения БД на сервере с моего локального компьютера, переключая конфигурацию проекта, открывая порт на машине с базой данных SQL и запуская:

> update-database -conf Log

в консоли диспетчера пакетов.

person Chris Moschini    schedule 11.09.2012