EF5 RF CF — Force Recovery Mode

Сложность 200

Или как заставить базу думать, что у вас новая модель.

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

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

Как мы выяснили еще в прошлый раз, все дело в поле Model, в котором теперь содержится не хэш модели, но вся модель в заархивированном виде, для того, чтобы можно было проводить анализ изменений, а не просто говорить, были изменения или нет.

Строго говоря, не делайте так, как я описал и сделал. Это словно бы противоречит самой природе подхода CodeFirst. В чем же прикуп тогда от системы, если она не будет самостоятельно генерировать скрипты обновлений и отслеживать состояние модели данных. Смысла в ручном написании скриптов по изменению схемы и потом менять классы – не много. Такие пустые миграции нужны для обновления данных и только, когда не меняется схема данных. Запомните!

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

Ладно, допустим, мы не вняли логике работы с CodeFirst, разработчики EF не сделали дополнительных проверок при обновлении базы данных – остается полагаться на свои силы и обновлять поле Model в таблице __MigrationHistory самостоятельно.

Таким образом, получается, что решить проблему могут следующие действия:

  • Надо получить логическую модель (.edmx файл)
  • Заархивировать ее
  • Записать в базу данных в последнее обновление в поле Model.

Получение логической модели

Как ни копайся в проекте, а в нем нет файла .edmx если работать по системе CodeFirst. Данный файл генерируется автоматически на лету с помощью класса EdmxWriter. Данный класс открытый и мы можем им воспользоваться в своих целях. Работа с классом очень простая, фактически у класса есть только один статический метод WriteEdmx(), который принимает контекст модели и XmlWriter.

Собственно все, в XmlWriter у нас будет XML модель контекста базы.

Архивирование

Для архивирования будет использоваться стандартный класс GZipStream.

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

Запись данных

В данном пункте тоже никаких особых сложностей быть не должно. Нам потребуется два элементарных SQL запроса, которые будут одинаковы для любой реляционной базы данных поддерживающей стандарт TSQL-92.

Первый запрос будет на получение MigrationId, второй на обновление поля Model по полученному ключу.

В целом код простой, но есть особенность с построением модели – она не  может быть построена при открытом соединении, поэтому при получении MigrationId я закрываю соединение. Так же в целях большего удобства для получения модели был выделен отдельный метод. Даже не знаю что тут можно прокомментировать.

По сигнатуре метода ForceUpdate() можно видеть, что я использую метод расширения.

 

В использовании все элементарно, однако я бы не стал создавать продуктовый код, который бы по анализу ошибки со скриншота запускал такой метод. Потому что это, действительно Force Update не взирая ни на какие условия.

Надеюсь данная заметка поможет вам в изучении и работе с EF5 Code First.

 

Hard’n’Heavy!

 

Violet Tape

 

 

Один комментарий на “EF5 RF CF — Force Recovery Mode

  1. Ааааа вот теперь понятно, что было сделано «не так». Для общего развития, конечно, почитал. Надо знать, как там все внутри устроено, но Вы абсолютно правы — так делать не надо.

Оставить комментарий