В данной статье хотел бы рассказать про набор полезных дополнений к Visual Studio, которые могут в значительной мере облегчить разработку баз данных на основе MS SQL Server.
Основными преимуществами использования SSDT я бы выделил следующее:
  • возможность простого изменения (refactoring) схемы базы (можно переименовать колонку таблицы и все Views, Functions и Stored Procedures ссылающиеся на неё автоматически будут исправлены для отражения изменений)
  • создание юнит тестов для базы данных
  • хранение структуры базы данных в Source Control
  • сравнение схемы/данных c возможностью генерации скрипта для приведения схемы/данных к требуемому состоянию

Безусловно на этом плюсы использования SSDT не заканчиваются, но остальное не так сильно впечатляет, как то, что упомянуто выше. Если вас интересует, как воспользоваться этими и другими преимуществами — прошу под кат.


Установка и первое знакомство


Всё необходимое для установки можно найти на странице загрузки в Data Developer Center. Выбрав необходимую версию вы сможете без труда установить инструменты на свой компьютер и описывать это не вижу смысла. После установки в окне создания нового проекта у вас появится новый тип проекта:


Создав новый проект вы увидите следующее:


На панели SQL Server Object Explorer (меню View -> SQL Server Object Explorer) мы видим нечто очень похожее на Object Explorer в SQL Server Management Studio, из которого убрано всё, что не имеет большого смысла на этапе разработки базы данных.
Подключившись к существующей базе, можно производить разработку базы данных в так называемом Connected режиме. Это мало чем отличается от классического подхода используемого в SQL Server Management Studio и в данной статье рассматриваться не будет.

Disconnected режим


Этот режим разработки нам наиболее интересен, т.к. именно он позволяет получить основные преимущества использования SSDT.
В основе работы лежит очень простая идея – позволить разработчикам хранить все скрипты создания объектов БД (tables, views, store procedures и т. д.) в проекте специального типа в составе имеющегося или нового решения (solution). На основе скриптов, Visual Studio может сгенерировать DACPAC файл, который по сути является zip архив со всеми t-sql скриптами. Имея DACPAC файл можно будет произвести публикацию (publish) на требуемом экземпляре базы данных, путём сравнения схемы описанной в DACPAC и схемы в целевой базе данных. В ходе публикации, специальные механизмы производят сравнения, в результате чего автоматически создаются миграционные скрипты для применения изменений без потери данных.
Для того что увидеть это в действии, предлагаю посмотреть следующие примеры.
Начнём с возможности импорта. Вызываем контекстное меню проекта и видим 3 возможных варианта:

  • Script (*.sql) – добавляет один или несколько *.sql файлов из заданного расположения в структуру проекта;
  • Data-tier Application (*.dacpac) – добавляет *.sql файлы, а так же различные настройки базы данных из специального DACPAC файла, описанного выше; может содержать не только схему базы, но так же данные и различные настройки базы;
  • Database… — аналогичен предыдущему варианту, но источником данных служит существующая база

Мы выберем вариант “Database…” и импортируем локальную базу. Она содержит одну таблицу и одну хранимую процедуру. В SQL Server Object Explorer исходная база выглядит следующим образом:

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

Так же мы всегда можем добавить новые элементы воспользовавшись диалоговым окном Add New Item, в котором перечислены все возможные объекты базы данных:

Добавим таблицу TestTable. Новый файл-скрипт TestTable.sql будет добавлен в корень проекта и для удобства мы его перенесём в папку Tables.

Для создания схемы таблицы мы можем использовать как панель дизайнера, так и панель T-SQL. Все изменения сделанные на одной панели будут сразу же отображены в другой.
Так же мы можем изменять существующие скрипты. Visual Studio для этого предоставляет удобный и любимый всеми IntelliSense. Так как мы не подключены к физической базе данных, Visual Studio для корректной работы IntelliSence парсит все скрипты в проекте, что позволяет ей мгновенно отражать последние изменения сделанные в схеме базы данных.

Хочу обратить внимание на то, что мы не должны заботиться об инкрементных изменениях нашей базы. Вместо этого мы всегда создаём скрипты так, как если бы объекты создавались заново. При публикации DACPAC пакета миграционные скрипты будут сгенерированы автоматически, путём сравнения DACPAC файла и схемы в целевой базе (target Database).
Как уже упоминалось, DACPAC содержит не только схему и данные, но ещё и ряд полезных настроек, для просмотра/редактирования которых мы можем воспользоваться окном свойств нашего проекта.

Свойство Target platform позволяет выставить версию базы данных, для которой будут валидироваться скрипты в проекте. Минимальная поддерживаемая версия MS SQL Server 2005. Если например задать версию базы 2005 и попробовать создать колонку типа Geography, то при компиляции мы получим следующее сообщение:

На закладке Project Settings, мы можем задать настройки базы данных, нажав на кнопку Database Settings. Нажав на неё мы увидим диалог с настройками, аналогичные тем, что мы привыкли видеть в SQL Server Management Studio:

Так же хочется упомянуть закладку SQLCMD Variables, на которой мы можем задавать различные переменные для дальнейшего их использования в наших скриптах.


Публикация DACPAC файла (publishing)


После того, как все настройки заданы и *.sql скрипты добавлены/обновлены мы можем применить изменения к целевой базе (target database). Для этого идём в меню Build->Publish или же выбираем аналогичный пункт в контекстном меню проекта.

В появившемся диалоговом окне задаём строку подключения к базе назначения (target database) и если необходимо — дополнительные настройки, нажав на кнопку Advanced:

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

Если требуется производить публикацию в целевую базу данных более одного раза, то настройки можно сохранить в publish профиль, нажав на кнопку Create Profile. Это добавит в наш проект файл с расширением *.publish.xml и в дальнейшем мы сможем произвести публикацию без необходимости вводить настройки ещё раз. Если же какой-то из профилей публикации должен быть использован по умолчанию, то можно в контекстном меню файла публикации выбрать пункт Set As Default Publish Profile. Этот профиль будет автоматически загружаться в диалог Publish.

Все необходимые изменения, можно применить сразу, нажав на кнопку Publish. А можно отложить на потом, сгенерировав соответствующий миграционный скрип (кнопка Generate Script) — он будет содержать все необходимые инструкции для приведения базы назначения к требуемому состоянию.
Если же у нас нет доступа к базе данных, то мы можем передать результаты нашего труда в виде DACPAC файла, который создаётся путём компиляции проекта и находится в ../bin/Debug/Database1.dacpac. Отдав файл, например, администратору базы данных, тот в свою очередь сможет воспользоваться любым удобным способом для применения изменений в целевой базе.
Способы публикации DACPAC (publishing):
  • Бесплатная редакция Visual Studio с установленными SSDT (в частности для publish используются клиентские инструменты, входящие в состав DAC Framework, устанавливаемые вместе с SSDT)
  • MS SQL Server Management Studio + DAC Framework
  • Консольная утилита SqlPackage.exe
  • Windows PowerShell (пример)
  • Data-tier Application Framework (DACFx) позволяющий поставить DACPAC файл, путём вызова методов из C# программы (документация и пример)

Data Seeding


В нашем проекте создадим папку DataSeeding (имя не имеет значения) и в неё добавим новый скрипт.

По сути все типы в разделе User Script являются обычными *.sql скриптами и отличаются лишь значением свойства “Build Action” у вновь созданного файла.

Логика из файла PostDeployment.sql будет выполнена после применения всех изменений схемы базы данных. В случае создания PreDeployment.sql — логика выполнится перед применением изменений схемы.
Значение свойства Build Action для файлов созданных через шаблон Script (Not in Build) будет установлено в «None». Они полезные для удобного структурирования команд в отдельных файлах, которые вызываются из Pre или Post Deployment скриптов.
Файлы созданные через шаблон Script имеют значение Build Action равное «Build», и их содержимое добавляется к результирующему скрипту, который выполняется при publish’e DACPAC файла в момент изменения схемы базы.
В виду того, что в проекте может быть только один Post Deployment script и его размер может быстро вырасти, рекомендуется логику вставки данных выносить в отдельные скрипты. Именно поэтому мы добавим файл типа Script (Not in Build), а в Post Deployment script добавим ссылку на него. Вот как это будет выглядеть:



Теперь при публикации нашего проекта, в базе всегда будут вставлены 2 записи в таблицу Employees.

Tools -> SQL Server


На ряду с возможностью создания Database проекта, установка SSDT добавляет ряд полезных инструментов, доступных из меню Tools.

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

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

В результирующем окне мы можем применить различные способы группировки (по схеме, по типу объектов и по требуемому действию) для более удобного просмотра предлагаемых изменений и выбрать те объекты, которые требуется обновить. Для того, что бы применить миграционный скрипт необходимо нажать кнопку Update – это приведёт Target DB к состоянию нашего проекта.

Refactoring


Это моя любимая фича. Для примера, покажем как переименовать колонку LastName в таблице Employees. Для этого открываем скрипт создания таблицы, в редакторе таблицы выделяем колонку LastName и в меню SQL -> Refactor выбираем пункт Rename:


Задаём новое имя:


Просматриваем последствия переименования и применяем предложенные изменения:


В результате все скрипты будут изменены и после первого рефакторинга в проект будет добавлен специальный файл *.refactoring. В нём будут сохраняться все изменения схемы в историческом порядке в формате XML документа. Эти данные будут полезны при генерации миграционного скрипта и позволят более правильно мигрировать схему и данные.


Unit testing


Создадим наш первый юнит тест. Для этого вызовем контекстное меню для хранимой процедуры, которую мы хотим протестировать:

В появившемся диалоговом окне у нас будет возможность выбрать дополнительные объекты (если они есть) и задать тип и имя тестового проекта и имя класса, содержащего код юнит теста:


Создав проект нам будет предложено выбрать базу данных на которой будут запускаться тесты, а также некоторые настройки проекта:


После успешного создания у нас откроется графический редактор юнит теста, в нижней части которого будут представлены различные проверки для тестируемого объекта. В нашем случае это хранимая процедура EmployeeGetList.

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


А вот так можно проверить Checksum:

По сути эта проверка выполняет наш скрипт (получает 2 строки из таблицы Employees) и на полученных данных находит Checksum. Наша задача на этапе создания теста, найти эталонные данные, на них посчитать Checksum и в дальнейшем с этим значением будет производиться сверка полученного результата. Иными словами, это удобный способ убедиться, что результат хранимой процедуры не меняется. Для получения контрольного значения Checksum, необходимо воспользоваться кнопкой в окне Properties, которая позволит выбрать эталонную базу и получить эталонное значение Cheсksum:


Заключение


Надеюсь этот краткий обзор позволил получить общее представление, что такое SSDT и как они могут быть полезны в вашем проекте. Безусловно тут не были рассмотрены все детали. Но вам, как разработчику это и не нужно. Вы должны просто иметь общее представление списка возможностей, а дальнейшее их использование надеюсь будет интуитивно понятным, т.к. разработчики SSDT хорошо потрудились и снабдили инструменты огромным количеством помощников (wizards) и контекстных подсказок.

Комментарии (25)


  1. lair
    27.04.2015 08:43
    -1

    На БД какого размера вы тестировали работоспособность этого подхода? Как себя поведет инструментарий, когда вам надо одновременно (и синхронно) поддерживать 20+ БД?


    1. kamilgarey
      27.04.2015 14:09

      Микросервисы?
      А связи между БД что-бы поддерживать целостность ключей?
      И/Или есть «тяжёлые» запросы включающие несколько БД?


      1. lair
        27.04.2015 14:18

        Адское legacy.


  1. david_off Автор
    27.04.2015 10:13

    Признаюсь, наша база не отличается слишком большим количеством объектов и объёмом данных (проект только начался). Но я не вижу причин, по которым этот подход может не сработать, если размер базы увеличится. Касательно поддержки «20+» — инструмент не даёт ни чего специального. В вашем случае я бы создал solution с отдельными Database проектами. Это позволит получить отдельный DACPAC для каждой базы и поставлять изменения по необходимости в каждую базу отдельно.


    1. lair
      27.04.2015 10:55

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

      Рефакторинг и построение изменений по десяткам тысяч объектов?

      Это позволит получить отдельный DACPAC для каждой базы и поставлять изменения по необходимости в каждую базу отдельно.

      А как же согласованные изменения? А отслеживание зависимостей между БД?


      1. david_off Автор
        27.04.2015 11:24

        Рефакторинг и построение изменений по десяткам тысяч объектов?

        Наверняка на такой базе процесс переименования будет проходить дольше, чем на нашей. Но всё равно он будет выполнен успешно и за умеренное время. Конретных цифр не могу привести, но склонен верить, что это будет не медленней, чем при использовании аналогичных иструментов (например SQL Bundle от Red Gate). Вообще на таких размерах думаю без использования чего-то подобного просто невозможно вести разработку и эти инструменты — MUST HAVE.

        А как же согласованные изменения? А отслеживание зависимостей между БД?

        Если вы используюте механизмы Linked Server или его аналоги (OPENDATASOURCE и OPENROWSET) и в хранимках или вьюхах одной базы на прямую задействованы объекты других баз (таблицы, вьюхи, хранимки), то конечено автоматически рефакторинг это не исправит. Но с другой стороны, если у вас действительно всё так организовано и часто меняются таблицы, от которых зависят внешние базы данных, то тут уже проблема подхода. Как по мне, не стоит напрямую использовать эти объекты из внешних баз, если они могут меняться.
        В свою очередь, будет интересно узнать, как вы сейчас боретесь с этими проблемами и есть ли какой альтернативный подход?


        1. lair
          27.04.2015 11:27
          -3

          Но всё равно он будет выполнен успешно и за умеренное время.

          Умеренное — это сколько? Час, два, десять?

          Вообще на таких размерах думаю без использования чего-то подобного просто невозможно вести разработку и это просто MUST HAVE.

          «Невозможно» — это «мы пробовали, и у нас не получилось», или «мы даже не пробовали»?

          Как по мне, не стоит напрямую использовать эти объекты из внешних баз, если они могут меняться.

          И как же с ними работать тогда?

          В свою очередь, будет интересно узнать, как вы сейчас боретесь с этими проблемами и есть ли какой альтернативный подход?

          Мы с ними боремся тестами.


          1. david_off Автор
            27.04.2015 12:01

            Умеренное — это сколько? Час, два, десять?

            Я уже писал что конкретных цифр не могу привести, но внутри одной базы рискну предположить что это будут секунды или десятки секунд, но ни как не часы. Всё-таки Resharper делает похожие вещи в C# коде и у меня был опыт работы с проектами, в которых были десятки тысяч файлов.

            «Невозможно» — это «мы пробовали, и у нас не получилось», или «мы даже не пробовали»?

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

            И как же с ними работать тогда?

            Затрудняюсь дать ответ конкретно по вашему случаю, т.к. для этого явно мало информации по вашему проету. Но наверняка можно, если не полностью убрать последствия переименования, то хотя бы свести их к минимуму. Возможно помогут механизмы репликации. Возможно пересмотр подходов к выборке: вместо SELECT'а из внешней базы можно вызывать во внешней базе хранимку и получить уже готовый результат. При этом подходе хранимка будет храниться в той же базе где и сама таблица и рефакторинг можно будет сделать при помощи предложенного инструмента (кроме конечно случая, когда сама эта хранимка переименовывается). Но в общем, нужно смотреть каджый проект в отдельности и давать советы только после близкого знакомства с ним.

            Мы с ними боремся тестами.

            SSDT не отменяют и не запрещают использование тестов. Наоборот, они упрощают их создание, чем в свою очередь способсвуют повышению степени покрытия тестами (легче тестить — можно за то же время больше покрыть). Об этот есть отдельный раздел в статье.

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


            1. lair
              27.04.2015 12:18
              -3

              Всё-таки Resharper делает похожие вещи в C# коде и у меня был опыт работы с проектами, в которых были десятки тысяч файлов.

              У Решарпера очень неслабый механизм анализа и кэширования его результатов. И все равно при включенном изменении строковых ссылок он ощутимо задумывается даже на тысячах файлов.

              Скорее пробывали и было крайне не удобно.

              На БД какого размера?

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

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

              Возможно пересмотр подходов к выборке: вместо SELECT'а из внешней базы можно вызывать во внешней базе хранимку и получить уже готовый результат. При этом подходе хранимка будет храниться в той же базе где и сама таблица и рефакторинг можно будет сделать при помощи предложенного инструмента (кроме конечно случая, когда сама эта хранимка переименовывается).

              А если меняется структура отдаваемых хранимкой данных или принимаемые ей параметры?

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

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


              1. david_off Автор
                27.04.2015 12:31
                +5

                Уважаемый, lair. Как я уже сказал, я не ставлю за цель убедить вас и ваших коллег в том, что бы вы пришли к использованияю SSDT. Каждый волен принимать решение по своему усмотрению. Если вы искренне верите, что SSDT вам будет больше мешать, чем помогать, то я не стану доказывать обратное. Наш с вами диалог понемногу начинает мне напоминать известную картинку, поэтому с Вашего позволения, я не буду продолжать это обсуждение и оставлю за собой право верить, что всё-таки найдутся читатели хабра, которым данный иструмент больше поможет, чем помешает и они будут рады узнать о его существовании.


              1. Dim0FF
                27.04.2015 22:11

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


                1. lair
                  27.04.2015 22:12

                  На разных серверах — никак (хотя есть DTC). На одном сервере — с помощью транзакций.


                  1. Dim0FF
                    27.04.2015 22:36

                    Я проверял публикацию БД на разных серверах как раз, видимо и SSDT обеспечить транзакционность не в состоянии, публиковать необходимо каждую базу отдельно.
                    Возможно, если БД на одном сервере, то и скрипт публикации будет один.


        1. Dim0FF
          27.04.2015 13:00

          Мы используем linked servera в разработке проектов. Зависимости между БД SSDT точно может отслеживать. Решается просто:

          • Добавить в solution все связанные БД.
          • Добавить переменную, которая будет ссылаться на linked сервер:
          • Аналогично добавить переменную, которая будет ссылаться на БД на этом сервере
          • Использовать в скриптах эти переменные:
            SELECT 
            dbo.Customers.Id,
            a.Id,
            FROM dbo.Customers
            LEFT OUTER JOIN [$(SrvSql1)].[$(Accounts)].dbo.account AS a ON dbo.Customers.Name = a.Name
            

          • При этом, если колонки a.Id в linked базе не будет, SSDT укажется на ошибку и не даст собрать проект

          Более того, при изменении в одном месте с помощью рефакторинга, SSDT автоматически меняет ссылки во всех связанных базах, так что согласованные изменения также возможны.
          Скорость рефакторинга проверить не могу, баз с десятками тысяч объектов нет.


          1. lair
            27.04.2015 13:02

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

            Пакет изменений генерится один на все БД?


            1. david_off Автор
              27.04.2015 13:16

              Для каждого проекта генерится отдельный DACPAC. Так как один проект представляет одну базу, я думаю в решении Dim0FF будут различные пакеты для каждой базы.


  1. Barada
    27.04.2015 15:05

    Это космос. Щас погонял на боевой базе. Компейр отрабатывает за секунд 20 на моей базе в 3к объектов. Чувствую моя жизнь станет много приятнее. Спасибо за инфу.


  1. Tsyoma
    27.04.2015 16:24

    Подскажите есть ли настройка или как сделать, чтобы при добавлении/изменении колонки в таблице в миграционных скриптах вместо DROP / CREATE был ALTER TABLE


    1. david_off Автор
      27.04.2015 17:29

      Перепроверил и не смог получить поведение с DROP/CREATE. Возможно я проверял на другой версии MS SQL Server, но мои результаты следующие: у меня была таблица Table с колонкой LastName; переименовал колонку в Surname и добавил новую колонку NewColumn; в результирующем миграционном скрипте вижу:

      --...
      EXECUTE sp_rename @objname = N'[dbo].[Table].[LastName]', @newname = N'Surname', @objtype = N'COLUMN';
      --...
      ALTER TABLE [dbo].[Table]
          ADD [NewColumn] INT NULL;
      --...
      


      Встречные вопросы:
      1) На какой версии сервера проверяли Вы?
      2) Какие именно вы проверяете скрипты? Ведь то что в проекте это не миграционные скрипты.
      3) Вы для переименовки пользовались функцией SQL-> Refactor-> Rename?


      1. Tsyoma
        27.04.2015 18:51

        Вы правы, если делать через рефакторинг то генерирует sp_rename и ALTER
        А я делал так:
        На локальной базе правил в Management Studio, затем через SqlSchemaCompare обновлял проект. И потом уже этот проект публиковал на другую базу.


  1. IamKarlson
    27.04.2015 22:07

    Вы забыли упомянунть про тип проекта Reporting Service. Без этого пакета с ssrs вообще тяжко работать когда отчетов много. Спасибо за инфу в массы.


    1. david_off Автор
      27.04.2015 22:49

      На самом деле не забыл, а умышленно пропустил. У меня с ним опыта практического очень мало. Для себя смотрел, но толково рассказать бы не смог, поэтому решил не портить статью куском «а бы что нибудь рассказать» и решил оставить это для других, например для Вас. Думаю Вы сможете написать статью, а на мою статью разрешаются сослаться, как на вступительную часть :).


  1. DrPass
    27.04.2015 23:19

    Что касается Reporting Service, Analysis Service, Integration Service (в общем, всё то, что раньше включала в себя BIDS), там всё очень грустно. По крайней мере, на мой взгляд. Со времен SQL Server 2008 в инструментарии не вылечена ни одна детская болячка, и можно сказать, он вообще не изменился за шесть лет, (если не считать такой важной фичи, как поддержка цветовых тем интерфейса).
    Вот самые печальные:
    В проекте Reporting Service до сих пор нельзя ни шаблоны ролей безопасности настроить, ни путь расположения отчета на сервере указать. Проект Analysis Service до сих пор страдает кошмаром для разработчика — если нехороший админ переименует хоть одну группу в AD, на которую завязаны роли в проекте, опубликовать его не получится. Но никак, ни под какой пыткой SSDT вам не признается, какая группа вызвала проблему, вам придется проверять их все поименно. А в Integration Service хотелось бы просто иметь что-то, хоть отдаленно похожее на вменяемый редактор скриптов, а не дикую мешанину текстовых полей и визуальных элементов.


    1. IamKarlson
      27.04.2015 23:28

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


  1. RouR
    28.04.2015 15:14

    Самая классная фича — это scheme compare, сравнить локальную, тестовую или продакшен базу, сгенерировать скрипт или сразу напрямую накатить изменения.