63 votes

Logique conditionnelle dans PostDeployment.sql script en utilisant 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 de base de données utilise un post-déploiement qui comprend un certain nombre d'autres scripts utilisant la syntaxe ":r" de SQLCMD.

J'aimerais pouvoir inclure de manière conditionnelle certains fichiers en fonction d'une variable SQLCMD. Cela me permettra d'exécuter le projet plusieurs fois dans le cadre de notre construction nocturne afin de configurer différentes versions de la base de données avec différentes configurations des données (pour un système multi-tenant).

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 je reçois une erreur de compilation : SQL01260 : Une erreur d'analyse fatale s'est produite : script.PostDeployment.sql

Est-ce que quelqu'un a vu cette erreur ou a réussi à configurer son script post-déploiement pour être flexible de cette façon ? Ou est-ce que je m'y prends complètement de travers ?

Merci, Rob

P.S. J'ai également essayé de modifier cette procédure pour que le chemin d'accès au fichier soit une variable, similaire à ce poste . Mais cela me donne une erreur disant que le chemin est incorrect.

41voto

Rob Bird Points 1471

UPDATE

Je viens de découvrir 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, ce qui rend la sytaxe invalide.

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

Pour tous ceux qui ont besoin de la même chose - J'ai trouvé ce message utile

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

  • script.PostDeployment.sql (fichier vide qui sera remplacé)
  • Default.script.PostDeployment.sql (liens vers les scripts nécessaires à la configuration standard des données)
  • 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 du projet (clic droit pour décharger et ensuite clic droit pour 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 définir les configurations de construction correspondantes dans la solution.

De plus, pour ceux qui essaient d'autres solutions, j'ai également essayé ce qui suit sans succès :

  1. Création d'un événement post build pour copier les fichiers au lieu d'avoir à pirater le fichier XML du projet. Je n'ai pas réussi à le faire fonctionner parce que je ne pouvais pas former le chemin correct vers le fichier script post déploiement. Ce numéro de connexion décrit le problème

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

0 votes

En ce qui concerne l'exigence de l'instruction GO, j'ai déjà contourné ce problème en exécutant l'instruction en tant que SQL dynamique. Mais ce n'était pas un projet de base de données MS. YMMV.

23voto

Simon Calvin Points 98

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

Donc, au lieu de ça :

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

J'ai inversé le conditionnel et mis NOEXEC ON de passer outre la ou les déclarations importées ainsi :

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

:r .\Configuration1\Data.sql

SET NOEXEC OFF

Assurez-vous de le désactiver à nouveau si vous voulez exécuter les déclarations suivantes.

15voto

Rob McCauley Points 176

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 Debug mais pas Release.

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

Nommez le fichier Debug.sqlcmdvars .

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

Répétez le processus pour créer un fichier Release.sqlcmdvars, en définissant les paramètres suivants $(BuildConfiguration) à libérer.

Maintenant, configurez vos configurations : Ouvrez la page des propriétés du projet à l'onglet Deploy. Dans la liste déroulante du haut, définissez la configuration comme étant Debug. Dans la liste déroulante du bas (variables de commande Sql), définissez le fichier comme Propriétés. \Debug.sqlcmdvars.

Répétez l'opération pour Release as : Dans la liste déroulante du haut, définissez la configuration comme étant Release. Dans la liste déroulante du bas (variables de commande Sql), définissez le fichier comme Propriétés. \Release.sqlcmdvars.

Maintenant, dans votre fichier script.PostDeployment.sql, vous pouvez spécifier la 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, faites un clic droit sur la solution de niveau supérieur et ouvrez le Gestionnaire de configuration. 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à, maintenant vos builds de développeur ont des données de test, mais pas votre release build !

9 votes

C'est 2015 et j'ai la dernière SSDT et VS2013 U4 et il n'y a pas d'onglet appelé "Deploy" et je n'ai même pas vu de moyen d'importer un fichier de variables SQLCMD. Vraiment confus

9voto

Dunc Points 4360

Comme Rob l'a constaté, les instructions GO ne sont pas autorisées dans les scripts SQL liés, car elles seraient imbriquées 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 placez-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é $(DeployTestData) qui me permet d'activer/désactiver le déploiement du test script.

3 votes

Je me suis également engagé dans cette voie, mais elle impose une exigence implicite selon laquelle tous les scripts doivent avoir des variables portant un nom unique. Cela peut être un problème avec des bases de données complexes.

1 votes

J'ai suivi cette voie et ça marche très bien. Merci !

3voto

kjbartel Points 453

J'ai trouvé un hack d'un blog MSDN ce qui a plutôt bien fonctionné. L'astuce consiste à écrire les commandes dans un fichier temporaire script, puis à exécuter ce script à la place. En gros, c'est l'équivalent du 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 site TempScript.sql Le fichier 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 GO etc. lorsqu'il est exécuté.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X