Comment puis-je conditionnellement inclure de gros scripts dans mon script de post-deployment ssdt?

Dans notre projet SSDT, nous avons un script énorme qui contient beaucoup d'instructions INSERT pour importer des données d'un ancien système. En utilisant les variables sqlcmd, j'aimerais pouvoir inclure le file dans le script de post-deployment.

Nous utilisons actuellement la syntaxe :r qui inclut le script en ligne:

 IF '$(ImportData)' = 'true' BEGIN :r .\Import\OldSystem.sql END 

Ceci est un problème car le script est inclus en ligne, que $(ImportData) soit vrai ou faux et que le file soit trop gros pour ralentir la compilation d'environ 15 minutes.

Existe-t-il un autre moyen d'inclure conditionnellement ce file de script afin qu'il ne ralentisse pas la construction?

Plutôt que de boueux ma réponse précédente avec un autre. Il y a un cas particulier avec une option TRÈS simple.

Créez des files d'input SQLCMD séparés pour chaque possibilité d'exécution. La key ici est de nommer les files d'input d'exécution en utilisant la valeur de votre variable de contrôle.

Par exemple, votre script de publication définit la variable 'Config' qui peut avoir l'une de ces valeurs: 'Dev', 'QA' ou 'Prod'.

Créez 3 scripts de post-deployment nommés 'DevPostDeploy.sql', 'QAPostDeploy.sql' et 'ProdPostDeploy.sql'.

Codez votre file post-deployment actuel comme ceci:

: r. "\" $ (Config) PostDeploy.sql

Cela ressemble beaucoup au mécanisme d'événement de génération dans lequel vous remplacez les scripts par des scripts appropriés, sauf que vous n'avez pas besoin d'un événement de génération. Mais vous dépendez de nommer vos scripts très spécifiquement.

Les scripts référencés utilisant: r sont toujours inclus. Vous avez quelques options, mais je vérifierais d'abord que si vous supprimez le script, les performances seront améliorées là où vous le souhaitez.

L'approche la plus simple consiste à la garder en dehors de tout le process de construction et à modifier votre process de deployment afin qu'il devienne une chose en deux étapes (déployer le DAC puis déployer le script). Les points positifs de ceci sont que vous pouvez faire des choses en dehors du process ssdt mais les négatifs sont que vous n'obtenez pas des choses comme la désactivation automatique des contraintes sur les tables changeant dans le deployment.

La deuxième consiste à ne pas inclure le script dans le deployment lorsque vous créez, mais créez une tâche msbuild AfterBuild qui ajoute le script en tant que script de post-deployment dans le DACPAC. Le dacpac est un file zip, vous pouvez donc utiliser l'empackageage .net Api pour append une partie appelée postdeploy.sql qui sera ensuite incluse dans le process de deployment.

Ces deux moyens signifient que vous perdez la vérification, donc vous pourriez vouloir le garder dans un projet ssdt séparé qui a une reference "même database" à votre projet principal, il ralentira la construction quand il change mais devrait être rapide le rest de la time.

Voici comment je devais le faire.

1) Créez un script post-deployment factice.

2) Créez des configurations de construction dans votre projet pour chaque scénario de deployment.

3) Utilisez un événement de pré-construction pour déterminer la configuration post-deployment à utiliser. Vous pouvez soit créer des scripts distincts pour chaque configuration, soit créer de manière dynamic le script post-deployment dans votre événement de pré-construction. De toute façon, vous basez ce que vous faites sur la valeur de $ (configuration) qui existe toujours dans un événement de construction.

Si vous utilisez des scripts statiques distincts, votre événement de génération doit uniquement copyr le file statique approprié, écrasant le post-deployment factice avec le script le plus utile dans ce scénario de deployment.

Dans mon cas, j'ai dû utiliser la génération dynamic car la décision concernant les scripts à inclure nécessitait de connaître l'état actuel de la database déployée. J'ai donc utilisé la variable de configuration pour me dire quel environnement était déployé et ensuite utilisé un script SQLCMD avec: OUT défini sur mon location de script Post-Deploy. Ainsi, mon script de pré-construction écrirait le script post-deployment de façon dynamic.

Dans tous les cas, une fois la construction terminée et le process de deployment normal démarré, le script Post-Deploy contenait exactement les commands: r que je voulais.

Voici un exemple du script SQLCMD que j'appelle dans la pré-construction.

 :OUT .\Script.DynamicPostDeployment.sql PRINT ' /*'; PRINT ' DO NOT MANUALLY MODIFY THIS SCRIPT. '; PRINT ' '; PRINT ' It is overwritten during build. '; PRINT ' Content IS based on the Configuration variable (Debug, Dev, Sit, UAT, Release...) '; PRINT ' '; PRINT ' Modify Script.PostDeployment.sql to effect changes in executable content. '; PRINT ' */'; PRINT 'PRINT ''PostDeployment script starting at''+CAST(GETDATE() AS nvarchar)+'' with Configuration = $(Configuration)'';'; PRINT 'GO'; IF '$(Configuration)' IN ('Debug','Dev','Sit') BEGIN IF (SELECT IsNeeded FROM rESxStage.StageRebuildNeeded)=1 BEGIN -- These get a GO statement after every file because most are really HUGE PRINT 'PRINT ''ETL data was needed and started at''+CAST(GETDATE() AS nvarchar);'; PRINT ' '; PRINT 'EXEC iESxETL.DeleteAllSchemaData ''pExternalETL'';'; PRINT 'GO'; PRINT ':r .\PopulateExternalData.sql '; .... 

J'ai fini par utiliser un mélange de notre outil de construction (Jenkins) et SSDT pour accomplir ceci. C'est ce que j'ai fait:

  1. Ajout d'une étape de génération à chaque travail Jenkins spécifique à l'environnement qui écrit dans un file text. J'écris une command SQLCMD qui inclut le file d'import ou bien je la laisse vide en fonction des parameters de construction que l'user choisit.
  2. Incluez le nouveau file text dans le script Post Deployment via :r .

C'est tout! J'utilise également cette même approche pour choisir les scripts pré et post-deployment à inclure dans le projet en fonction de la version de l'application, sauf que je récupère le numéro de version du code et l'écris au file en utilisant un événement pré-build dans VS de dans l'outil de construction. (J'ai aussi ajouté le nom du file text à .gitignore afin qu'il ne soit pas .gitignore )