Pull to refresh

Comments 46

Написано от души, спасибо за статью. И за ECM7
А Вам спасибо за проявленный интерес! ;)

Сейчас есть идея относительно еще одного поста про мигратор. В ближайшее время постараюсь написать его.
некоторое время назад я написал небольшую библиотеку, которая на основе linq-прототипов «конструирует» БД и вносит изменения в неё. единственный недостаток пока — работает только с MS SQL. да и наверное всегда только с ней и работать будет. отсюда вопрос — интересно ли это хабралюдям, писать статью о библиотеке с примерами или нет?
Есть хороший способ проверить это — написать ;)
здравствуйте :) ну как там еще один пост про мигратор? :) или уже и не ждать?
ждите! обязательно будет!

сейчас завал по работе… поэтому временная пауза.
меня тут как раз напрягли разобраться с мигратором (после вашей статьи кстати) :))) так что новая была бы очень полезна :)
это был не упрек ))) а то я как-то странно написала ))
если у Вас появятся вопросы — Вы пишите… обязательно постараюсь помочь.
спасибо за предложение :) вполне возможно что понадобится ваша помощь :)
Спасибо за материал. Новые веяния в дотнете радуют больше других новостей.
Спасибо! Добавлю в закладки чтоб не потерять. =)
Добавил себе в закладки, поскольку сейчас параллельно с основной веткой разработки нашего проекта на Delphi начата работа над .Net вариантом.

К слову, наш проект работает с двумя базами: Oracle и Firebird. И если изменения в физической структуре БД Oracle почти всегда осуществимы, в худшем случае зависимые объекты станут (возможно, на время, до последующих команд миграции) инвалидными — это всегда можно поправить, перекомпилировав по окончании миграции основные схемы своей БД, то в Firebird все не так просто. Наличие зависимых объектов просто не позволит выполнить ряд операций (например, у нас предустматриваются по три view на каждую таблицу (для выборки, обновления и удаления, и уже на эти view раздаются права пользователям) и в подавляющем числе случаев выглядят как select * from ). В описанном мной случае нельзя будет поменять тип существующих полей таблицы, удалить существующие поля. Поэтому в нашей системе обновлений таблиц предусматривается полное устранения зависимостей перед началом операций и затем попытка их воссоздания (с перераздачей сохраненных перед удалением прав).

Возможно, по мере развития вашего мигратора вам придется столкнуться с Firebird. Рад буду помочь!
Спасибо за интересный комментарий!

По поводу Firebird:
Доработки в ECM7.Migrator в основном выполнялись «для себя». На работе мы используем Oracle и MS SQL Server. Поэтому основные усилия были направлены на улучшение работы с этими СУБД. По этой же причине был удален провайдер для PostgreSQL — нет реальных проектов, использующих эту СУБД, мы не сможем нормально протестировать этот провайдер и не сможем его поддерживать.

И по этой же причине нет провайдера и для Firebird.
Если я столкнусь в работе с Firebird, то обязательно добавлю соответствующий провайдер и обращусь к Вам за помощью ;)

С другой стороны, если Вы захотите использовать Migrator при работе с Firebird, я готов создать для Вас «шаблон» нового диалекта, который вы сможете изменять на основе своего опыта. Также буду рад ответить на любые Ваши вопросы.
Некоторое время назад искал подобные вещи под .net-стек, но не смог найти, радует, что появились сейчас, т.к. это очень полезный контроль над структурой бд.
Что касается версионности БД в проектах на .NET, то у меня все обстояло следующим образом:

Сначала была просто табличка в БД, в которую каждый скрипт писал о своем выполнении. Польза — при ее просмотре можно было определить, что выполнялось, а что нет. Скрипты запускали руками через GUI (Management Studio).

Потом была написана программа с GUI, которая сравнивала номера скриптов в папке (номер из названия файла) с выполненными скриптами, а потом по очереди запускала не выполненные скрипты. Программа была довольно кривой и не универсальной. Работала только на MS SQL Server.

Далее была написана другая программа, на этот раз для проекта под Oracle. Она имела более четкую структуру, лучше парсила скрипты. GUI не было, зато имелось консольное приложение и таск для NAnt. Эта программа до сих пор используется на нескольких проектах (веб-приложения), в т.ч. при выкладки на «боевую» систему.

Собственно, после этого открыли для себя мигратор. Пока не спешим переводить все проекты на него, т.к. сейчас нет времени и старая программа выполнения скриптов более-менее устраивает. Но что-то новое пишем уже с использованием мигратора. Пока все очень нравится.
А почему нет диалекта для MS SQL?)
Есть. Просто автор написал вместо MS SQL — SQL Server :)
почему же?
все есть
>> В проекте Migrator.NET есть «диалекты» для следующих СУБД:
>> MySQL, Oracle, SQLite, SQL Server, PostgreSQL

сейчас исправлю на «MS SQL Server»
Сурово как-то, чтобы мигрировала БД нужно писать код, программу. Мне удобнее использовать мержилку для БД, которая сравнивает БД и генерит скрипты для перехода от dev версии к production(предположим, или от версии 1 к 2), с возможностью контроля, разумеется.
Мержилка для БД — просто другой подход. У него свои достоинства и свои недостатки.

Пример недостатка — такой подход в результате формирует папку с большим количеством скриптов, которую менее удобно выполнять и распространять пользователям.

Про достоинства писать не буду — они очевидны.

Каждый выбирает тот подход, который ему больше нравится.
Кстати, вы возможно работали с мержилками, есть что-нибудь лучшее для Oracle, чем продукт от EMS?
К сожалению, большого опыта работы с мержилками у меня нет :(

Кратко смотрел программы от EMS для MS SQL Server и для Oracle. Посмотрел их очень кратко, т.к. не было времени. С другими подобными программами, к сожалению, не сталкивался.

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

Насчет удобства распространения пользователям — это да, не все наверное смогут выполнить SQL скрипт, более того если в бд были внесены конфликтующие изменения — сложнее отследить эту ситуацию ( хотя тут пользователь — ссзб).
Забыл добавить — студийный DataDude проводит верификацию всяких хранимых процедур и функций на предмет правильности вызовов — совпадения имен, параметров.
Т.е. если в вызове ХП будет использован столбец которого нт в БД — поднимется крик. Этакой компилятор для SQL структур.

А ваши продукты такое умеют?
Мигратор не умеет проверять корректность названий объектов БД.
Действительно, для этого будет лучше выбрать студийные утилиты.

Единственное, я не совсем понял вот это предложение:
>> утилиты из DataDude генерят один файл, который содержит все изменения

Я думаю, любая программа, генерирующая diff для двух БД может сохранить свои результаты в один общий файл. Проблема не в этом. Один общий файл выполняет перевод БД из состояния А в состояние Б. Как быть, если нужно перевести БД в состояние Б не из состояния А, а из какого-то промежуточного состояния В?

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

Второй вариант — иметь такие файлы, переводящие БД последовательно из состояния V в состояние V+1. В этом случае мы как раз и получаем папку с кучей скриптов.

— И еще по поводу того, что все скрипты завернуты в транзакции. К сожалению, в Oracle это не поможет, т.к. Oracle выполняет каждую команду DDL в отдельной транзакции. Мне приходится работать с Oracle и его работа с транзакциями стала еще одной причиной, почему я использую мигратор.

Если Вы работаете, например, с MS SQL Server, то вы находитесь в другой ситуации и свободны выбрать любое другое средство.
вот такой вот он особенный Оракл!
на самом деле откат всегда можно сделать — собирать комманды уже выполненные, с сохранением состояний которые были, но здесь всегда возникнет проблема хранения таких данных, если например stored procedure можно как нибудь сохранить, то с удаляемыми столбцами сложнее — нужно искать Unique/Pk индекс и сохранять в отдельных таблицах данные, но возможно =)

в любом случае такое усложнение логики может привести к невозможности использования утилиты как таковой.

про один файл — как правило если продукт делается для конторы, то там есть свои DBA, которые ни в коем случае не дадут вам модифицировать структуру, так что генерировать один файл вариант. к тому же если приложение само при запуске обновляет базу данных необходимо задуматься о синхронизации нескольких экземпляров, что бы не накатить дважды. с другой стороны если вы делаете руками обновление базы, то в вашем приложении необходимо проверять всегда версию базы данных. то есть варианта только два файлик апдейта, и селф db checking.

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

Вы правы. Мы тоже думали об этом и пришли к аналогичному мнению.

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

Думаю, универсального решения нет и действия должны зависеть от каждой конкретной ситуации.
Результат работы диффа — сравнение базы и проекта\двух проектов\двух баз.
Соответственно для баз или проект-база генерится скрипт (в виде одного файла) который при выполнении приводит target db к source Db (source project). Если надо перевести A->Б — это один скрипт, если надо В-> Б — это другой.
Собственное если вы пишете на C# и есть 2008 студия — можете попробовать сами — создание проекта бд, импорт в него существующей базы и диффы (в том числе по данным) делаются достаточно просто. Но это конечно только для SQL Server =) Извините, MS-Stack.

PS Я не стараюсь критиковать ваше решение, просто привел пример еще одного удачного решения проблем с проектом БД. Кстати можете позаимствовать оттуда идею верификации полей в ХП — это вроде реально сделать если есть интерфейс извлечения данных о структуре самой БД.
Полностью с Вами согласен. На счет диффов — я именно это и имел в виду. Мы с Вами говорили об одном и том же. Я так увлекся доказыванием своей точки зрения, что не заметил ее совпадение с Вашей.

>> Я не стараюсь критиковать ваше решение, просто привел
>> пример еще одного удачного решения проблем с проектом БД.

Согласен с Вами. Вариантов очень много. Мигратор лишь один из них, причем далеко не в каждой ситуации его использование будет удачным решением проблемы.
Попиарюсь и я. Точнее, напомню. Принцип у Wizardby немного другой: специальный язык, с помощью которого описываются изменения схемы БД.
Ах ты ж ё-моё. Невнимательно прочел заключительный пассаж. Прошу прощения.
Раз уж Вы увидели этот пост, можете сравнить Ваш проект с проектом Migrator.NET?
Готов ответить на любые Ваши вопросы.
Попробую что-то внятное сообразить. Все нижеследующее — мое субъективное мнение.

Прежде всего, мне не нравится сама идея писать миграции в C#-коде: очень «неинтерактивный» получается цикл. Открыть в студии класс, написать миграции вверх-вниз, скомпилировать, запустить. У Wizardby как-то всё пошустрее: есть консоль, есть Notepad++. Там поправил, переключил, wizardby u/redo/down — и все.

Второе: непонятна ситуация с назначением таймстемпов миграций. Руками его сочинять грустно; гораздо удобнее, когда само средство за тебя подставляет всё, что надо.

Третье: синтаксис слегка побогаче (но тут сложнее — у вас-то вообще C#-код, который, очевидно, Тюринг-полный и делать там можно вообще все, что захочется). Алиасы типов, шаблоны таблиц, «вывод типов» и вывод названий столбцов.
Спасибо!

А можете представить в виде таблицы?
В строках критерии оценки, в столбцах — мигратор и wizardby.

Если у Вас сейчас нет возможности, то я позже сам составлю такую. Очень интересно было бы сравнить.

Нет, сейчас абсолютно нет времени. Но если что — спрашивайте, буду рад ответить.
круто! за идею мега плюс!

есть только один момент пусть в версии V использовался столбец невычислимый f в таблице t, при переходе на V+1 он удаляется, в таком случае в методе down нужно предусматривать восстановление.
тулза может сама архивировать такие данные, но с другой стороны получится куча мусора, и при добавлении кортежей в t при работе в версии V+1 мы не сможем создать невычислимое f, хотя — не часто откат проиходит в продакшене
На счет удаления и восстановления столбцов Вы правы. Тут единственный выход — аккуратно писать миграции и продумывать их работу в таких случаях.

Еще вариант — делать резервные копии БД при переходе на следующую версию. Все-таки, мигратор вряд ли самостоятельно сможет обеспечить полноценную версионность БД с данными. Скорее он обеспечивает версионность структуры БД.

По поводу идеи — очень рад, что Вам понравилось! Только идея не моя, я всего лишь принял участие в ее реализации.

Если решите использовать мигратор, буду рад ответить на любые Ваши вопросы ;)
ну вопросы просто беглые как всегда
1. он сохраняет каррент версию бд?
2. Migration X всегда мигрирует с X-1 на X?
3. как дела с транзакционностью? то есть наверное если что то упало, то нужно за собой почистить, и судя по интерфейсу об этом нужно вспомнить самому разработчику?
1. Если под словами «каррент версия» вы имеете в виду «номер каррент версии», то дело обстоит следующим образом: есть таблица (при отсутствии генерируется автоматом при первом запуске миграций), в которую записаны номера выполненных миграций. Максимальный номер — и есть номер текущей версии.

2. Нет. Мигратор выполняет миграции в порядке возрастания номера версии, но не обязательно, чтобы они отличались на 1. На сайте оригинального проекта приводят пример, когда в качестве номера версии указывается дата создания миграции: 20081104133052 — для времени 13:30:52 4 ноября 2008 года (номер версии — Int64).

3. Мигратор оборачивает каждую миграцию в транзакцию. К сожалению, это прокатывает не во всех СУБД. Например, Oracle при выполнении команд DDL каждую такую команду оборачивает в отдельную транзакцию, а если транзакция уже была открыта, она принудительно коммитится. В этом случае разработчику нужно внимательно следить за выполнением миграций. Как вариант — можно еще размещать в каждой миграции ровно по одной команде DDL. В этом случае будет много мелких классов, зато гарантированно будут откатываться изменения в случае ошибок.

Вообще, чем меньше изменение в каждой отдельной миграции — тем лучше.
Спасибо за статью. Хотелось бы более тонко прочувствовать миграции на примерах диаграмм и графиков, но даже так вполне понятно.
Полностью согласен! Информация в графическом виде намного нагляднее.

Единственное, поясните, пожалуйста, что именно вы хотели бы узнать из диаграмм. Если получится, постараюсь собрать статистику и нарисовать их.
Хочется видеть визуально как это мердженье работает, то есть например написованую схему 1, схему 2, какой код написан в обоих случаях, что реально происходит в момент «перехода», и т.д.
Есть идея записать скринкаст, в котором с нуля написать несколько миграций.
Мне кажется, такой вариант будет еще более наглядным и будет восприниматься лучше, чем куча текста.

Как появится свободное время — займусь этим.
Интересно, а есть ли практическая польза от даунгрейда базы? Кроме общепрограммисткого «сделали, потому что можем».

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

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

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

— По поводу «простого набора SQL в отдельном файле» я уже писал предыдущим комментаторам.

Мигратор, как и SQL-файл — просто разные решения одной проблемы. У них обоих есть свои достоинства и недостатки.

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

Я думаю, нужно выбирать способ, который вам привычнее, а также, нужно обязательно учитывать ситуацию, в которой Вы планируете его применять.
Sign up to leave a comment.

Articles