Как заставить 'Schema Compare' для Database->SQL Project учитывать переменные SQL-CMD

У меня есть решение Visual Studio 2013 с 2 проектами SQL DB1, DB2.

DB1 имеет хранимую процедуру, которая ссылается на DB2.

Если я использую.dacpac и синонимы в процедурах

SELECT * FROM [$(DB2)].[dbo].[Table1]

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

Если вместо этого я использую

SELECT * FROM DB2.[dbo].[Table1]

и измените тип сборки хранимой процедуры на None (чтобы проект собирался), тогда сравнение схемы при переходе от базы данных к проекту ** не будет "видеть" сохраненный процесс в моем проекте и добавит новый процесс в проект базы данных SQL на каждом сравнить

После сравнения схемы теперь увижу

  • DB1
    • ПСЭ
      • Хранимые процедуры
        • sp_myStoredProcedure.sql
        • sp_myStoredProcedure1.sql
        • sp_myStoredProcedure n.sql

где n = количество схем сравнивается!

Если был способ игнорировать Build Error SQL7501, то он должен работать, используя второй вариант, но, похоже, его нельзя игнорировать.

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

Это похоже на простой и распространенный вариант использования. Кто-то придумал обходной путь для этого недостатка дизайна?

Обновить

После проверки ответа Кевина я выяснил, почему некоторые из моих взглядов не были правильно обработаны с помощью SC. Его ответ технически правильный, однако:

Если у вас есть представление в DB1:

SELECT * FROM DB1.dbo.Table1 T1
INNER JOIN DB2.dbo.Table2 T2 
ON T2.Field1 = T1.Field1

а в вашем DB1 SQL Project оригинал (без самостоятельной ссылки DB1)

SELECT * FROM dbo.Table1 T1
INNER JOIN [$(DB2)].dbo.Table2 T2 
ON T2.Field1 = T1.Field1

При сравнении схемы не удастся правильно заменить переменную и определить изменение: [$(DB2)] -> $(DB2)

Проблема заключается в собственной ссылке DB1.dbo.Table, которая в моем случае была вставлена ​​на полпути большого количества объединений, многие из которых были ссылками DB2.

Это приводит к тому, что SC ошибочно помечает все [$ (DB2)] как изменения. Возможно, потому что база данных sql не "строится" в VS и возвращается к сравнению текста.

Так что это на самом деле не ошибка, а сложный результат для разработчика, который не сравнивает вручную каждую строку SQL.

Я думаю, что эта проблема может быть расширена до следующего:

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

Я также должен добавить, что в моем случае DB2 также ссылается на DB1!

Это может быть причиной неправильного сообщения об ошибках.

В конце, чтобы избежать циклических зависимостей (проекты не могут ссылаться друг на друга), я построил DB1, ссылающуюся на DB2, используя ссылку на проект, но проверяя "ошибки сборки подавления в ссылочном проекте". DB2 не была собрана, потому что она ссылалась на DB1.

Затем, собрав DB1, я использовал выходной DACPAC в папке bin, скопировал его в другое место и в DB2 сослался на этот DB1 DACPAC. Теперь каждый раз, когда изменяется DB1, мне приходится перестраивать копию DACPAC в эту папку. К счастью для меня это не изменится слишком сильно.

Весь этот процесс очень запутанный, и проекты SQL должны позволять ссылаться друг на друга (с удаленным подавлением ошибок), но, в конце концов, мне удалось получить 2 дБ, которые ссылаются друг на друга, чтобы быть построенными, и все с совместимыми синонимами и сравнением схем!

И это заняло всего 2 дня борьбы!

https://connect.microsoft.com/VisualStudio/feedback/details/1291555

1 ответ

Решение

Эту проблему можно избежать, изменив настройки SQLCMD Variables Default или Local в свойствах проекта базы данных. Поведение таково: - если определено локальное значение, это то, что используется в сравнении схем; - если локальное значение не определено, вместо него будет использоваться значение по умолчанию. Поэтому обновление значения Local в соответствии с именем базы данных, на которое вы ссылаетесь, перестройка и сравнение новой схемы должны решить эту проблему для вас.

Параметры переменной SQLCMD - локальные переопределения По умолчаниюЕсли у вас есть несколько баз данных, на которые вы хотите настроить таргетинг, лучшим вариантом сейчас является установка разных значений для значения "Local" в зависимости от вашей конфигурации. Это означает, что:

  1. Вы создаете новую Конфигурацию решения в диалоговом окне Build -> Configuration Manager для каждой цели. Это позволяет вам изменять некоторые настройки и изменять их в зависимости от конфигурацииConfiguration Manager - создать новую конфигурацию
  2. Вы редактируете файл projectname.sqlproj.user, который должен быть в основе вашего решения. Он содержит значение Local для базы данных, и вы можете изменить значение в зависимости от конфигурации. В моем примере у меня была только 1 переменная $(DB2), и она сопоставлена ​​с параметром SqlCmdVar__1 в пользовательских настройках. Я изменил это с:

    отлаживать

Для того, чтобы:

<SqlCmdVar__1 Condition=" '$(Configuration)' == 'Debug' ">Debug</SqlCmdVar__1>
<SqlCmdVar__1 Condition=" '$(Configuration)' == 'Release' ">Release</SqlCmdVar__1>

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

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

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

  • Создайте проекты "DB1_Core" и "DB2_Core". Поместите объекты, на которые ссылаются другие базы данных, в основной проект
  • В вашем проекте DB1 добавьте "DB1_Core" в качестве ссылки "Та же база данных". Это будет гарантировать, что при публикации с "Включить составные объекты = true", что ваш проект DB1 публикует так же, как и раньше, - все объекты Core будут включены.
  • Сделайте то же самое для проекта DB2
  • Для DB1 нужна только ссылка на DB2_Core, а для DB2 - DB1_Core. Это нарушает круговую зависимость и позволяет безопасно строить.

Это лучшая практика, которая следует шаблонам, аналогичным C# и другим типам проектов. Существует презентация, посвященная составным проектам - ссылка находится в блоге SSDT здесь.

Другие вопросы по тегам