management - La lógica condicional en el script PostDeployment.sql usando SQLCMD
sqlcmd login (6)
Así es como estoy manejando la implementación condicional dentro del proceso posterior a la implementación para desplegar los datos de prueba para la configuración de depuración pero no de liberación.
Primero, en el explorador de soluciones, abra la carpeta de propiedades del proyecto y haga clic con el botón derecho para agregar un nuevo archivo SqlCmd.variables.
Denomine el archivo Debug.sqlcmdvars
.
Dentro del archivo, agregue sus variables personalizadas y luego agregue una variable final llamada $(BuildConfiguration)
y establezca el valor en Debug.
Repita el proceso para crear Release.sqlcmdvars, configurando $(BuildConfiguration)
en Release.
Ahora, configure sus configuraciones: abra la página de propiedades del proyecto a la pestaña Implementar. En el menú desplegable superior, configure la configuración para que sea Debug. En el menú desplegable inferior, (variables de comando Sql), establezca el archivo en Propiedades / Debug.sqlcmdvars.
Repita para la versión como: En el menú desplegable superior, configure la configuración para que sea Release. En el menú desplegable inferior, (variables de comando Sql), establezca el archivo en Properties / Release.sqlcmdvars.
Ahora, dentro de su archivo Script.PostDeployment.sql, puede especificar la lógica condicional, como:
IF ''Debug'' = ''$(BuildConfiguration)''
BEGIN
PRINT ''***** Creating Test Data for Debug configuration *****'';
:r ./TestData/TestData.sql
END
En el explorador de soluciones, haga clic derecho en la solución de nivel superior y abra Configuration Manager. Puede especificar qué configuración está activa para su compilación. También puede especificar la configuración en la línea de comando MSBUILD.EXE.
Ahí lo tienes, ahora tus compilaciones de desarrollador tienen datos de prueba, ¡pero no tu versión de lanzamiento!
Estoy usando un proyecto de base de datos SQL 2008 (en Visual Studio) para administrar el esquema y los datos de prueba iniciales para mi proyecto. El proyecto de atabase usa una implementación posterior que incluye un número de otras secuencias de comandos que usan la sintaxis ": r" de SQLCMD.
Me gustaría poder incluir de manera condicional ciertos archivos basados en una variable SQLCMD. Esto me permitirá ejecutar el proyecto varias veces con nuestra compilación nocturna para configurar varias versiones de la base de datos con diferentes configuraciones de los datos (para un sistema multi-tenant).
He probado lo siguiente:
IF (''$(ConfigSetting)'' = ''Configuration1'')
BEGIN
print ''inserting specific configuration''
:r ./Configuration1/Data.sql
END
ELSE
BEGIN
print ''inserting generic data''
:r ./GenericConfiguration/Data.sql
END
Pero obtengo un error de compilación: SQL01260: se ha producido un error fatal del analizador: Script.PostDeployment.sql
¿Alguien ha visto este error o ha logrado configurar su script de post-despliegue para ser flexible de esta manera? ¿O estoy haciendo esto por el camino equivocado por completo?
Gracias, Rob
PD. También intenté cambiar esto para que la ruta al archivo sea una variable similar a esta publicación . Pero esto me da un error al decir que la ruta es incorrecta.
Como Rob resolvió, las declaraciones GO no están permitidas en los scripts SQL enlazados, ya que esto anidaría dentro de las instrucciones BEGIN / END.
Sin embargo, tengo una solución diferente a la suya, si es posible, elimine cualquier instrucción GO de las secuencias de comandos a las que se hace referencia y coloque una sola después de la instrucción END:
IF ''$(DeployTestData)'' = ''True''
BEGIN
:r ./TestData/Data.sql
END
GO -- moved from Data.sql
Tenga en cuenta que también he creado una nueva variable en mi archivo sqlcmdvars llamada $ (DeployTestData) que me permite activar / desactivar el despliegue del script de prueba.
Encontré un truco de un blog de MSDN que funcionó bastante bien. El truco es escribir los comandos en un archivo de script temporal y luego ejecutar ese script. Básicamente el equivalente de SQL dinámico para 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
El archivo TempScript.sql
contendrá:
print ''inserting specific configuration'';
:r ./Configuration1/Data.sql
o
print ''inserting generic data'';
:r ./GenericConfiguration/Data.sql
dependiendo del valor de $(ConfigSetting)
y no habrá problemas con las declaraciones GO
, etc. cuando se ejecute.
Me inspiré en la solución de Rob Bird. Sin embargo, simplemente estoy usando Build Events para reemplazar los scripts posteriores a la implementación en función de la configuración de compilación seleccionada.
- Tengo un script de implementación de publicación "ficticio" vacío.
- Configuré un evento de preconstrucción para reemplazar este archivo "ficticio" en función de la configuración de compilación seleccionada (ver imagen adjunta).
- Configuré un evento posterior a la creación para volver a colocar el archivo "ficticio" después de que la construcción haya finalizado (ver imagen adjunta). La razón es que no quiero generar cambios en el control de cambios después de la compilación.
ACTUALIZAR
Ahora descubrí que la sintaxis if / else anterior no funciona para mí porque algunos de mis scripts vinculados requieren una declaración GO. Básicamente, r solo importa los scripts en línea, por lo que se convierte en sytax no válido.
Si necesita una declaración GO en las secuencias de comandos vinculadas (como yo) entonces no hay una forma fácil de hacerlo, terminé creando varias secuencias de comandos posteriores a la implementación y luego cambiando mi proyecto para sobrescribir la secuencia de comandos posterior de despliegue en tiempo de compilación en la configuración de compilación. Esto ahora está haciendo lo que necesito, ¡pero parece que debería haber una manera más fácil!
Para cualquier persona que necesite lo mismo, esta publicación me resultó útil
Entonces, en mi proyecto tengo los siguientes archivos de implementación posterior:
- Script.PostDeployment.sql (archivo vacío que se reemplazará)
- Default.Script.PostDeployment.sql (enlaces a scripts necesarios para la configuración de datos estándar)
- Configuration1.Script.PostDeployment.sql (enlaces a scripts necesarios para una configuración de datos específica)
Luego agregué lo siguiente al final del archivo del proyecto (haga clic derecho para descargar y luego haga clic con el botón secundario en editar):
<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>
Finalmente, deberá configurar las configuraciones de compilación correspondientes en la solución.
Además, para cualquier persona que intente otro trabajo alternativo, también intenté lo siguiente sin suerte:
Crear un evento posterior a la compilación para copiar los archivos en lugar de tener que hackear el archivo XML del proyecto. No pude hacer que esto funcione porque no pude formar la ruta correcta para el archivo de script posterior a la implementación. Este problema de conexión describe el problema
Usar variables para que la ruta del script pase al comando: r. Pero encontré varios errores con este enfoque.
Logré solucionar el problema utilizando el método noexec .
Entonces, en lugar de esto:
IF (''$(ConfigSetting)'' = ''Configuration1'')
BEGIN
print ''inserting specific configuration''
:r ./Configuration1/Data.sql
END
Invertí el condicional y configuré NOEXEC ON para omitir la (s) declaración (es) importada (s) de esta manera:
IF (''$(ConfigSetting)'' <> ''Configuration1'')
SET NOEXEC ON
:r ./Configuration1/Data.sql
SET NOEXEC OFF
Asegúrese de desactivarlo si desea ejecutar cualquier declaración posterior.