Автоматическая миграция БД в Entity Framework

    В процессе разработки ПО, когда ещё не весь функционал определён окончательно, структура БД часто изменяется. И если используется какой-либо ORM-framework, изменение БД после изменения модели данных доставляет некоторые неудобства (по сути нужно проделать двойную работу по изменению класса модели и структуры БД). Вкратце, как сделать миграцию в EF4 Code First с помощью Package Manager Console описано здесь, я же постараюсь описать как работает автоматическая миграция без участия разработчика (точнее, при минимальном участии).


    С чего всё началось


    Встала задача создания нового проекта, представляющего из себя что-то вроде АРМа.
    Посовещавшись, решили использовать Entity Framework Code First, т.к. в перспективе возможна смена СУБД, а с этим вариантом нам нужно будет просто сменить строку соединения (если имеется подходящий ADO.NET провайдер).
    Сделали модели данных, класс контекста, наследуемый от DbContext'а:

    public class ProjectContext : DbContext
    {
        public ProjectContext()
        {
        }
    
        public ProjectContext(string connString)
            : base(connString)
        {
        }
    
        public DbSet<Address> Addresses { get; set; }
        ...
    }

    добавили инициализатор:

    public class ProjectInitializer : DropCreateDatabaseIfModelChanges<ProjectContext>
    {
        protected override void Seed(ProjectContext context)
        {
             ...
        }
    }

    и прописываем (в нашем случае в Global.asax) инициализатор:

    Database.SetInitializer(new ProjectInitializer());

    Всё вроде замечательно, у кого базы нет она создаться, но после уточнения у заказчика деталей, возникла необходимость добавить ещё сущности. А так как разработку ведут несколько разработчиков, произошло массовое пересоздание БД, а данные там уже реальные лежали.

    Миграции


    Так мы пришли к миграциям. Как советует статья выполнили в Package Manager Console команду:

    PM> Add-Migration 1
    

    В проекте появилась папка Migrations, в которой создалось два файла: Configuration.cs, <дата_время>_1.cs. Первый, как следует из названия конфигурация миграции, второй содержит необходимые изменения БД для обновления/отката версии. Далее достаточно выполнить в консоли NuGet'а:

    PM> Update-Database
    

    Всё было замечательно, если у кого-то модель не совпадала с БД, он просто делал миграцию в консоли и удалял файлик с миграцией. Пока не пришло время разместить проект на сервере заказчика. NuGet'а там не было, и установить возможности тоже не было (а у хостинг-провайдера такая возможность, отсутствует в принципе, если не берёте сервер).

    Автоматическая миграция


    Пытаясь выяснить, как делать автоматическую миграцию, вооружившись IntelliSense, методом научного тыка эмпирическим методом выяснили, что нужно сменить класс, от которого наследуется инициализатор:

    //public class ProjectInitializer : DropCreateDatabaseIfModelChanges<ProjectContext>
    public class ProjectInitializer : MigrateDatabaseToLatestVersion<ProjectContext, Configuration>
    {
         ...
    }
    

    Запустили и получили такое исключение:



    Ага! Делаем, то, что предлагается в сообщении исключения, то есть:

    public sealed class Configuration : DbMigrationsConfiguration<ProjectContext>
    {
        public Configuration()
        {
            AutomaticMigrationsEnabled = true;
        }
    
         protected override void Seed(ProjectContext context)
         {
               
         }
    }
    

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



    Дело в том, что с точки зрения Entity Framework переименование свойства есть удаление и добавления с новым именем, а таким образом возможно потеря данных. В таких случаях (а их бывает немного), просто нужно создать миграцию вручную командой Add-Migration и поправить вручную DropColumn и CreateColumn на RenameColumn (или ещё что-то, в зависимости от ситуации).

    Заключение


    На этом всё, надеюсь статья будет полезной. А также надеюсь, что информации от первоисточника по данному вопросу очень мало, потому-что это как-бы бета-версия и с релизом Entity Framework 5.0, не придётся методом проб и ошибок искать правильный вариант использования.

    Similar posts

    AdBlock has stolen the banner, but banners are not teeth — they will be back

    More
    Ads

    Comments 22

      +2
      А также надеюсь, что информации от первоисточника по данному вопросу очень мало, потому-что это как-бы бета-версия и с релизом Entity Framework 5.0, не придётся методом проб и ошибок искать правильный вариант использования.

      Зря надеетесь. Информации вполне достаточно.
        +3
        На вопрос про миграции не смогли ответить эксперты и докладчики Microsoft на конференции WebProfessionals. Если бы информация была бы столь доступна, я думаю ответили бы незамедлительно.

        А так могу сказать, что везде почему-то предлагают выполнять Add-Migration/Update-Database и везде пропускается информация об инициализаторе, наследованом от MigrateDatabaseToLatestVersion, без которого автомиграции не выполняются.
          +2
          Кстати, если есть ссылка, по которой всё это объясняется (без консольных команд Add-Migration/Update-Database), буду рад её увидеть.
        +2
        Посовещавшись, решили использовать Entity Framework Code First, т.к. в перспективе возможна смена СУБД, а с этим вариантом нам нужно будет просто сменить строку соединения


        какие еще варианты рассматривали?

        полезный фрэймворк для миграции — FluentMigrator
          +2
          NHibernate и eXpress Persistent Objects (XPO). О миграциях тогда не задумывались, нужно было просто, чтобы была возможность пересесть на другую СУБД.
            0
            какое ограничение у NHibernate при переходе на другую СУБД?
              +1
              Да собственно никаких, само использование ORM не понравилось (ISession, DeattachedCriteria), показалось лишних действий больше при использовании. Смотрели очень быстро, на раздумья 2 часа было:)
                0
                Ну в подавляющем большинстве (громадном большинстве), кроме сессии-то ничего и не надо. А сессия — это аналог DbContext.
            +1
            Посмотрел мельком FluentMigrator, очень похож в использовании на EntityFramework Migrations. Есть принципиальные преимущества?
              0
              с EF Migrations не работал, так что сравнивать не могу.

              EntityFramework Migrations только с EF может работать? или ORM ему не важен?
                0
                Не могу сказать, но очень похоже, что только EntityFramework, ему обязательно нужен наследник DbContext'а из этого ORM.
            0
            «Всё вроде замечательно, у кого базы нет она создаться»
            Вообще-то, инициализатор DropCreateDatabaseIfModelChanges делает ровно то, что написано в названии — дропает БД при изменениях модели. Правда же, очень полезное поведение?
              +1
              Когда делаешь проект один и тестовых данных достаточно (и не предполагается поддержка/изменение), то и DropCreateAlways сойдёт. К сожалению, такое бывает очень редко и в таком случае DropCreateDatabaseIfModelChanges действительно бесполезен, более того может навредить, если вовремя не сделать бэкап.
              +1
              Извиняюсь за оффтоп, но я бы «отрефакторил» имя класса :)
                0
                Contex? :)
                  0
                  Самое смешное, что в реальном проекте тоже Contex (ведь из него и скопипастено и изменено начало слова). В статье поправил, завтра поправлю на работе:)
                    0
                    А вообще, т.к. проект напрямую связан с медициной, то название самое то;)
                      0
                      Да можно оставить, хоть какая-то несерьезность будетт :)
                0
                Не то чтобы я против nhiber'а, но почему-то по старинке все еще пишу на нем. Хотя уже вроде даже миграции есть.
                  +1
                  Рекомендую заинтересованным посмотреть Entity Framework Code First Migrations, довольно подробно она рассказывает, видео совсем короткое, после просмотра я сразу начал искать книжку данного автора, которая приятно меня удивила.
                    0
                    Именно поэтому я выбираю ADO.NET для уверенности и полном контроле на работой с БД, потому что БД это самое«узкое место» в любом практически приложении. Однако, когда надо сделать что-то по-быстрому, то CodeFirst в помощь. Более того надеюсь в будущем EF станет действительно революционном прорывом по всем показателям, что сможет заменить ADO.NET в полном объеме.

                    Only users with full accounts can post comments. Log in, please.