Обещал рассказать о способе, которым пользуемся мы для обеспечения синхронизации некоторого количества баз данных.
Для начала вкратце обрисую задачу.
Есть несколько баз данных: дивелоперская, тестовая (та, на которой выполняются юнит и функциональны тесты), UAT (user acceptance test), на которой работают тестеры и немножко – маркетеры, pre-production (используется для проведения презентаций и т.д). В свете очень скорого релиза предполагается появление одной и более production базы данных.
Дивелоперская версия “эволюционирует” в режиме реального времени, в то время, как обновление UAT происходит автоматически по расписанию (это делает Team Build) и, понятное дело, нужно производить обновление базы данных в момент обновления продукта, то есть, в составе этого самого билда. Остальные базы – та же история, в момент обновления инсталяции.
Кроме того, понятное дело, каждая база данных хранит свои собственные данные. То есть, содержимое всех баз абсолютно разное и должно оставаться абсолютно разным. А вот структура данных должна быть одинаковая. Структура – это и схема БД, и состояние данных. То есть, если по каким-то причинам вдруг понадобилось увеличить цену продуктов на 20% (дурацкий пример), то сделать это нужно во всех базах, а продукты везде разные.
В общем, мы пробовали пользоваться различным софтом для сравнения и синхронизации схем БД, автоматизировать его, как-то проверять периодически на предмет, не напутал ли он чего (ведь может быть в девелоперской базе есть что-то, что и не нужно, чтобы было больше нигде), а уж DML эти (это я про “увеличить цену” как отслеживать…
В общем, мы пришли к очень простому, но действенному методу. Я, кстати, не верил, что будет так эффективно, когда начинали. Оказалось – очень неплохо.
Смысл метода заключается в том, что все изменения, которые делаются в БД, делаются посредством SQL-скриптов (а я предупреждал, что метод простой).
Скрипты, согласно конвенции, именуются в порядке очередности: 00129.sql, 00130.sql и т.д. Они хранятся в папке scripts одного из проектов в solution.
База данных содержит табличку SchemaVersion с одним числовым полем (TFS поступает так же, если я не ошибаюсь).
Проект, в котором это все лежит, называется DatabaseMigrator. Все, что он делает – читает из config-файла connection strings, подключается к базам, смотрит в SchemaVersion и исполняет скрипты, версия (имя) которых выше, чем то, что находится в БД. Выполнил – обновил версию.
Вот и все.
А дальше – для каждой конфигурации – просто свой app.config-файл. Team Build запускает DatabaseMigrator каждый раз, когда делает обновление UAT. Другие билды, которые обновляют другие инсталяции, делают то же самое.
Работать с этим всем совсем просто: каждый раз, когда мне нужно изменить схему, поменять структуру данных или что-то еще, я создаю sql-файлик и запускаю migrator. Прошло – отлично, дивелоперская и тестовая базы обновлены, можно работать. UAT и прочее – обновятся своевременно. При этом если я что-то напортачил в скрипте, то просто “упадет” билд – и ничего не сломается на существующей инсталяции.