Как заставить '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 в соответствии с именем базы данных, на которое вы ссылаетесь, перестройка и сравнение новой схемы должны решить эту проблему для вас.
Если у вас есть несколько баз данных, на которые вы хотите настроить таргетинг, лучшим вариантом сейчас является установка разных значений для значения "Local" в зависимости от вашей конфигурации. Это означает, что:
- Вы создаете новую Конфигурацию решения в диалоговом окне Build -> Configuration Manager для каждой цели. Это позволяет вам изменять некоторые настройки и изменять их в зависимости от конфигурации
Вы редактируете файл 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 здесь.