web-dev-qa-db-fra.com

Logique conditionnelle dans le script PostDeployment.sql à l'aide de SQLCMD

J'utilise un projet de base de données SQL 2008 (dans Visual Studio) pour gérer le schéma et les données de test initiales de mon projet. Le projet atabase utilise un post-déploiement qui comprend un certain nombre d'autres scripts utilisant la syntaxe ": r" de SQLCMD.

Je voudrais pouvoir inclure conditionnellement certains fichiers basés sur une variable SQLCMD. Cela me permettra d'exécuter le projet plusieurs fois avec notre build nocturne pour configurer différentes versions de la base de données avec différentes configurations des données (pour un système multi-locataire).

J'ai essayé ce qui suit:

IF ('$(ConfigSetting)' = 'Configuration1')
  BEGIN
    print 'inserting specific configuration' 
:r .\Configuration1\Data.sql
  END
ELSE
  BEGIN
    print 'inserting generic data' 
:r .\GenericConfiguration\Data.sql
  END

Mais j'obtiens une erreur de compilation: SQL01260: Une erreur fatale de l'analyseur s'est produite: Script.PostDeployment.sql

Quelqu'un a-t-il vu cette erreur ou réussi à configurer son script de post-déploiement pour être flexible de cette manière? Ou est-ce que je me trompe complètement?

Merci, Rob

P.S. J'ai également essayé de changer cela pour que le chemin d'accès au fichier soit une variable, similaire à cet article . Mais cela me donne une erreur en disant que le chemin est incorrect.

52
Rob Bird

[~ # ~] mise à jour [~ # ~]

J'ai maintenant découvert que la syntaxe if/else ci-dessus ne fonctionne pas pour moi car certains de mes scripts liés nécessitent une instruction GO. Essentiellement, le: r importe simplement les scripts en ligne, donc cela devient une syntaxe invalide.

Si vous avez besoin d'une instruction GO dans les scripts liés (comme je le fais), il n'y a pas de moyen facile de contourner cela, j'ai fini par créer plusieurs scripts de post-déploiement puis en modifiant mon projet pour écraser le script de post-déploiement principal au moment de la construction en fonction de sur la configuration de construction. Cela fait maintenant ce dont j'ai besoin, mais il semble qu'il devrait y avoir un moyen plus simple!

Pour tous ceux qui ont besoin de la même chose - j'ai trouvé cet article utile

Donc dans mon projet, j'ai les fichiers de post-déploiement suivants:

  • Script.PostDeployment.sql (fichier vide qui sera remplacé)
  • Default.Script.PostDeployment.sql (liens vers les scripts nécessaires à la configuration de données standard)
  • Configuration1.Script.PostDeployment.sql (liens vers les scripts nécessaires pour une configuration de données spécifique)

J'ai ensuite ajouté ce qui suit à la fin du fichier de projet (clic droit pour décharger puis clic droit modifier):

  <Target Name="BeforeBuild">
      <Message Text="Copy files task running for configuration: $(Configuration)" Importance="high" />
      <Copy Condition=" '$(Configuration)' == 'Release' " SourceFiles="Scripts\Post-Deployment\Default.Script.PostDeployment.sql" DestinationFiles="Scripts\Post-Deployment\Script.PostDeployment.sql" OverwriteReadOnlyFiles="true" />
      <Copy Condition=" '$(Configuration)' == 'Debug' " SourceFiles="Scripts\Post-Deployment\Default.Script.PostDeployment.sql" DestinationFiles="Scripts\Post-Deployment\Script.PostDeployment.sql" OverwriteReadOnlyFiles="true" />
      <Copy Condition=" '$(Configuration)' == 'Configuration1' " SourceFiles="Scripts\Post-Deployment\Configuration1.Script.PostDeployment.sql" DestinationFiles="Scripts\Post-Deployment\Script.PostDeployment.sql" OverwriteReadOnlyFiles="true" />
  </Target>

Enfin, vous devrez installer des configurations de build correspondantes dans la solution.

De plus, pour tous ceux qui essaient d'autres solutions, j'ai également essayé ce qui suit sans aucune chance:

  1. Création d'un événement post-génération pour copier les fichiers au lieu de devoir pirater le fichier de projet XML. je n'ai pas pu faire fonctionner cela parce que je n'ai pas pu former le chemin correct vers le fichier de script de post-déploiement. Ce problème de connexion décrit le problème

  2. Utilisation de variables pour le chemin du script à passer à la commande: r. Mais j'ai rencontré plusieurs erreurs avec cette approche.

36
Rob Bird

J'ai réussi à contourner le problème en utilisant la méthode noexec .

Donc, au lieu de cela:

IF ('$(ConfigSetting)' = 'Configuration1')
 BEGIN
    print 'inserting specific configuration' 
    :r .\Configuration1\Data.sql
 END

J'ai inversé le conditionnel et défini NOEXEC ON pour ignorer les instructions importées ainsi:

IF ('$(ConfigSetting)' <> 'Configuration1')
    SET NOEXEC ON

:r .\Configuration1\Data.sql

SET NOEXEC OFF

Assurez-vous de le désactiver si vous souhaitez exécuter des instructions ultérieures.

18
Simon Calvin

Voici comment je gère le déploiement conditionnel dans le processus de post-déploiement pour déployer les données de test pour la configuration de débogage mais pas de version.

Tout d'abord, dans l'Explorateur de solutions, ouvrez le dossier des propriétés du projet et cliquez avec le bouton droit pour ajouter un nouveau fichier SqlCmd.variables.

Nommez le fichier Debug.sqlcmdvars.

Dans le fichier, ajoutez vos variables personnalisées, puis ajoutez une variable finale appelée $(BuildConfiguration) et définissez la valeur sur Debug.

Répétez le processus pour créer un Release.sqlcmdvars, en définissant $(BuildConfiguration) sur Release.

Maintenant, configurez vos configurations: Ouvrez la page des propriétés du projet dans l'onglet Déployer. Dans la liste déroulante supérieure, définissez la configuration sur Debug. Dans la liste déroulante inférieure, (variables de commande SQL), définissez le fichier sur Properties\Debug.sqlcmdvars.

Répétez l'opération pour Release as: dans la liste déroulante supérieure, définissez la configuration sur Release. Dans la liste déroulante inférieure, (variables de commande SQL), définissez le fichier sur Properties\Release.sqlcmdvars.

Maintenant, dans votre fichier Script.PostDeployment.sql, vous pouvez spécifier une logique conditionnelle telle que:

IF 'Debug' = '$(BuildConfiguration)'
BEGIN
PRINT '***** Creating Test Data for Debug configuration *****';
:r .\TestData\TestData.sql
END

Dans l'Explorateur de solutions, cliquez avec le bouton droit sur la solution de niveau supérieur et ouvrez Configuration Manager. Vous pouvez spécifier quelle configuration est active pour votre build. Vous pouvez également spécifier la configuration sur la ligne de commande MSBUILD.EXE.

Voilà, vos versions de développeur contiennent des données de test, mais pas la version finale!

15
Rob McCauley

Au fur et à mesure que Rob a travaillé, les instructions GO ne sont pas autorisées dans les scripts SQL liés car cela les imbriquerait dans les instructions BEGIN/END.

Cependant, j'ai une solution différente de la sienne - si possible, supprimez toutes les instructions GO des scripts référencés et mettez-en une seule après l'instruction END:

IF '$(DeployTestData)' = 'True'
BEGIN
    :r .\TestData\Data.sql
END
GO -- moved from Data.sql

Notez que j'ai également créé une nouvelle variable dans mon fichier sqlcmdvars appelée $ (DeployTestData) qui me permet d'activer/désactiver le déploiement du script de test.

8
Dunc

J'ai trouvé un piratage sur un blog MSDN qui fonctionnait assez bien. L'astuce consiste à écrire les commandes dans un fichier de script temporaire, puis à exécuter ce script à la place. Fondamentalement, l'équivalent de SQL dynamique pour SQLCMD.

-- Helper newline variable
:setvar CRLF "CHAR(13) + CHAR(10)"
GO
-- Redirect output to the TempScript.sql file
:OUT $(TEMP)\TempScript.sql

IF ('$(ConfigSetting)' = 'Configuration1')
  BEGIN
    PRINT 'print ''inserting specific configuration'';' + $(CRLF)   
    PRINT ':r .\Configuration1\Data.sql' + $(CRLF)
  END
ELSE
  BEGIN
    PRINT 'print ''inserting generic data'';' + $(CRLF) 
    PRINT ':r .\GenericConfiguration\Data.sql' + $(CRLF)
  END
GO
-- Change output to stdout
:OUT stdout

-- Now execute the generated script
:r $(TEMP)\TempScript.sql
GO

Le fichier TempScript.sql Contiendra alors soit:

print 'inserting specific configuration';   
:r .\Configuration1\Data.sql

ou

print 'inserting generic data';
:r .\GenericConfiguration\Data.sql

en fonction de la valeur de $(ConfigSetting) et il n'y aura aucun problème avec les instructions GO etc. lors de son exécution.

2
kjbartel

J'ai été inspiré par la solution de Rob Bird. Cependant, j'utilise simplement les événements de génération pour remplacer les scripts de post-déploiement basés sur la configuration de génération sélectionnée.

  1. J'ai un script de déploiement post "factice" vide.
  2. J'ai mis en place un événement de pré-build pour remplacer ce fichier "factice" basé sur la configuration de build sélectionnée (voir photo ci-jointe).
  3. J'ai mis en place un événement post-build pour replacer le fichier "factice" une fois la build terminée (voir photo ci-jointe). La raison en est que je ne souhaite pas générer de modifications dans le contrôle des modifications après la génération.

Build Events setup example

2
Martin Karouš