Nota:
El acceso a esta página requiere autorización. Puede intentar iniciar sesión o cambiar directorios.
El acceso a esta página requiere autorización. Puede intentar cambiar los directorios.
Puede crear colaboradores de implementación para realizar acciones personalizadas al implementar un proyecto de SQL. Puede crear un DeploymentPlanModifier o un DeploymentPlanExecutor. Utilice un DeploymentPlanModifier para cambiar el plan antes de que se ejecute y un DeploymentPlanExecutor para realizar operaciones mientras se ejecuta el plan. En este tutorial, creará un DeploymentPlanModifier denominado SqlRestartableScriptContributor. DeploymentPlanModifier SqlRestartableScriptContributor agrega IF instrucciones a los lotes del script de implementación para permitir que el script vuelva a ejecutarse repetidamente hasta que se completen exitosamente si se produce un error durante la ejecución.
En este tutorial, se llevan a cabo las principales tareas siguientes:
- Crear el tipo de colaborador de implementación DeploymentPlanModifier
- Instalar el colaborador de implementación
- Ejecutar o comprobar su colaborador de implementación
Requisitos previos
Necesitará los componentes siguientes para completar este tutorial:
Debe haber instalado una versión de Visual Studio que incluya SQL Server Data Tools y admita el desarrollo de C#.
Debe disponer de un proyecto de SQL que contenga los objetos SQL.
Una instancia de SQL Server a la que pueda implementar un proyecto de base de datos.
Nota
Este tutorial está destinado a usuarios que ya están familiarizados con las características de SQL de SQL Server Data Tools. También se espera que esté familiarizado con los conceptos básicos de Visual Studio, como cómo crear una biblioteca de clases y cómo usar el editor de código para agregar código a una clase.
Creación de un colaborador de implementación
Para crear un colaborador de implementación, debe realizar las siguientes tareas:
- Cree un proyecto de biblioteca de clases y agregue las referencias necesarias.
- Defina una clase denominada SqlRestartableScriptContributor que herede de DeploymentPlanModifier.
- Invalide el método OnExecute.
- Agregue métodos del asistente privados.
- Compile el ensamblado resultante.
Creación de un proyecto de biblioteca de clases
- Cree un proyecto de bibliotecas de clases de Visual C# (.NET Framework) llamado MyOtherDeploymentContributor.
- Cambie el nombre del archivo “Class1.cs” a “SqlRestartableScriptContributor.cs”.
- En el Explorador de soluciones, haga clic con el botón derecho en el nodo del proyecto y seleccione Agregar referencia.
- En la pestaña Frameworks, seleccione System.ComponentModel.Composition.
- En el menú Proyecto, seleccione Administrar paquetes NuGet. Instale las versiones estables más recientes para Microsoft.SqlServer.DacFx.
A continuación, empiece a agregar el código a la clase.
Defina la clase SqlRestartableScriptContributor
En el editor de código, actualice el archivo class1.cs para que coincidan las siguientes instrucciones using:
using System; using System.Collections.Generic; using System.Globalization; using System.Text; using Microsoft.SqlServer.Dac.Deployment; using Microsoft.SqlServer.Dac.Model; using Microsoft.SqlServer.TransactSql.ScriptDom;Actualice la definición de clases para que coincida con el ejemplo siguiente:
/// <summary> /// This deployment contributor modifies a deployment plan by adding if statements /// to the existing batches in order to make a deployment script able to be rerun to completion /// if an error is encountered during execution /// </summary> [ExportDeploymentPlanModifier("MyOtherDeploymentContributor.RestartableScriptContributor", "1.0.0.0")] public class SqlRestartableScriptContributor : DeploymentPlanModifier { }Ahora ha definido un colaborador de implementación que hereda del DeploymentPlanModifier. Durante los procesos de compilación e implementación, los colaboradores personalizados se cargan desde un directorio de la extensión estándar. Los colaboradores que modifican el plan de implementación se identifican con un atributo ExportDeploymentPlanModifier. Este atributo es necesario para poder detectar colaboradores. Este atributo deberá ser parecido al decorador de función siguiente:
[ExportDeploymentPlanModifier("MyOtherDeploymentContributor.RestartableScriptContributor", "1.0.0.0")]Agregue las declaración de miembro siguientes:
private const string BatchIdColumnName = "BatchId"; private const string DescriptionColumnName = "Description"; private const string CompletedBatchesVariableName = "CompletedBatches"; private const string CompletedBatchesVariable = "$(CompletedBatches)"; private const string CompletedBatchesSqlCmd = @":setvar " + CompletedBatchesVariableName + " __completedBatches_{0}_{1}"; private const string TotalBatchCountSqlCmd = @":setvar TotalBatchCount {0}"; private const string CreateCompletedBatchesTable = @" if OBJECT_ID(N'tempdb.dbo." + CompletedBatchesVariable + @"', N'U') is null begin use tempdb create table [dbo].[$(CompletedBatches)] ( BatchId int primary key, Description nvarchar(300) ) use [$(DatabaseName)] end ";A continuación, invalide el método de OnExecute para agregar el código que desea ejecutar cuando se implementa un proyecto de base de datos.
Sobrescribir OnExecute
Agregue el método siguiente a la clase SqlRestartableScriptContributor:
/// <summary> /// You override the OnExecute method to do the real work of the contributor. /// </summary> /// <param name="context"></param> protected override void OnExecute(DeploymentPlanContributorContext context) { // Replace this with the method body }Invalide el método OnExecute de la clase base, DeploymentPlanContributor. DeploymentPlanContributor es la clase base para DeploymentPlanModifier y DeploymentPlanExecutor. Un objeto DeploymentPlanContributorContext se transfiere al método OnExecute, lo que proporciona acceso a cualquier argumento especificado, al modelo de base de datos de origen y de destino, al plan de implementación y a las opciones de implementación. En este ejemplo, obtenemos el plan de implementación y el nombre de la base de datos de destino.
Ahora agregue los principios de un cuerpo el método OnExecute:
// Obtain the first step in the Plan from the provided context DeploymentStep nextStep = context.PlanHandle.Head; int batchId = 0; BeginPreDeploymentScriptStep beforePreDeploy = null; // Loop through all steps in the deployment plan while (nextStep != null) { // Increment the step pointer, saving both the current and next steps DeploymentStep currentStep = nextStep; nextStep = currentStep.Next; // Add additional step processing here } // if we found steps that required processing, set up a temporary table to track the work that you are doing if (beforePreDeploy != null) { // Add additional post-processing here } // Cleanup and drop the table DeploymentScriptStep dropStep = new DeploymentScriptStep(DropCompletedBatchesTable); base.AddAfter(context.PlanHandle, context.PlanHandle.Tail, dropStep);En este código, definimos algunas variables locales, y configuramos el bucle que controlará el procesamiento de todos los pasos del plan de implementación. Una vez completado el bucle, tenemos que realizar algún procesamiento posterior y, a continuación, quitar la tabla temporal que creamos durante la implementación para realizar un seguimiento del progreso a medida que se ejecuta el plan. Los tipos de clave aquí son: DeploymentStep y DeploymentScriptStep. Un método clave es AddAfter.
Ahora agregue el procesamiento del paso adicional, para reemplazar el comentario “Agregar el procesamiento del paso adicional aquí”:
// Look for steps that mark the pre/post deployment scripts // These steps are always in the deployment plan even if the // user's project does not have a pre/post deployment script if (currentStep is BeginPreDeploymentScriptStep) { // This step marks the beginning of the predeployment script. // Save the step and move on. beforePreDeploy = (BeginPreDeploymentScriptStep)currentStep; continue; } if (currentStep is BeginPostDeploymentScriptStep) { // This is the step that marks the beginning of the post deployment script. // We do not continue processing after this point. break; } if (currentStep is SqlPrintStep) { // We do not need to put if statements around these continue; } // if we have not yet found the beginning of the pre-deployment script steps, // skip to the next step. if (beforePreDeploy == null) { // We only surround the "main" statement block with conditional // statements continue; } // Determine if this is a step that we need to surround with a conditional statement DeploymentScriptDomStep domStep = currentStep as DeploymentScriptDomStep; if (domStep == null) { // This step is not a step that we know how to modify, // so skip to the next step. continue; } TSqlScript script = domStep.Script as TSqlScript; if (script == null) { // The script dom step does not have a script with batches - skip continue; } // Loop through all the batches in the script for this step. All the // statements in the batch are enclosed in an if statement that checks // the table to ensure that the batch has not already been executed TSqlObject sqlObject; string stepDescription; GetStepInfo(domStep, out stepDescription, out sqlObject); int batchCount = script.Batches.Count; for (int batchIndex = 0; batchIndex < batchCount; batchIndex++) { // Add batch processing here }Los comentarios de código explican el procesamiento. En un nivel superior, este código busca los pasos que le interesan, saltándose otros y deteniéndose cuando se alcanza el principio de los pasos posteriores a la implementación. Si el paso contiene instrucciones que debemos rodear con condicionales, realizamos un procesamiento adicional. Entre las propiedades, métodos y tipos clave se encuentran los siguientes componentes de la biblioteca de DacFx: BeginPreDeploymentScriptStep, BeginPostDeploymentScriptStep, TSqlObject, TSqlScript, Script, DeploymentScriptDomStep y SqlPrintStep.
Ahora, agregue el código de procesamiento por lotes reemplazando el comentario “Agregar procesamiento por lotes aquí”:
// Create the if statement that contains the batch's contents IfStatement ifBatchNotExecutedStatement = CreateIfNotExecutedStatement(batchId); BeginEndBlockStatement statementBlock = new BeginEndBlockStatement(); ifBatchNotExecutedStatement.ThenStatement = statementBlock; statementBlock.StatementList = new StatementList(); TSqlBatch batch = script.Batches[batchIndex]; int statementCount = batch.Statements.Count; // Loop through all statements in the batch, embedding those in an sp_execsql // statement that must be handled this way (schemas, stored procedures, // views, functions, and triggers). for (int statementIndex = 0; statementIndex < statementCount; statementIndex++) { // Add additional statement processing here } // Add an insert statement to track that all the statements in this // batch were executed. Turn on nocount to improve performance by // avoiding row inserted messages from the server string batchDescription = string.Format(CultureInfo.InvariantCulture, "{0} batch {1}", stepDescription, batchIndex); PredicateSetStatement noCountOff = new PredicateSetStatement(); noCountOff.IsOn = false; noCountOff.Options = SetOptions.NoCount; PredicateSetStatement noCountOn = new PredicateSetStatement(); noCountOn.IsOn = true; noCountOn.Options = SetOptions.NoCount; InsertStatement batchCompleteInsert = CreateBatchCompleteInsert(batchId, batchDescription); statementBlock.StatementList.Statements.Add(noCountOn); statementBlock.StatementList.Statements.Add(batchCompleteInsert); statementBlock.StatementList.Statements.Add(noCountOff); // Remove all the statements from the batch (they are now in the if block) and add the if statement // as the sole statement in the batch batch.Statements.Clear(); batch.Statements.Add(ifBatchNotExecutedStatement); // Next batch batchId++;Este código crea una
IFinstrucción junto con unBEGIN/ENDbloque . A continuación, realizamos un procesamiento adicional en las declaraciones del lote. Una vez completado, agregamos unaINSERTinstrucción para agregar información a la tabla temporal que realiza un seguimiento del progreso de la ejecución del script. Por último, actualice el lote y reemplace las instrucciones que solían estar allí con el nuevoIFque contiene esas instrucciones. Los tipos de clave, los métodos y las propiedades incluyen: IfStatement, BeginEndBlockStatement, StatementList, TSqlBatch, PredicateSetStatement, SetOptions e InsertStatement.Ahora, agregue el cuerpo del bucle de procesamiento de instrucciones. Reemplace el comentario “Agregar el procesamiento de la instrucción adicional aquí”:
TSqlStatement smnt = batch.Statements[statementIndex]; if (IsStatementEscaped(sqlObject)) { // "escape" this statement by embedding it in a sp_executesql statement string statementScript; domStep.ScriptGenerator.GenerateScript(smnt, out statementScript); ExecuteStatement spExecuteSql = CreateExecuteSql(statementScript); smnt = spExecuteSql; } statementBlock.StatementList.Statements.Add(smnt);Para cada instrucción del lote, si la instrucción es de un tipo que se debe encapsular con una
sp_executesqlinstrucción , modifique la instrucción en consecuencia. A continuación, el código agrega la instrucción a la lista de instrucciones delBEGIN/ENDbloque que creó. Los tipos, métodos y propiedades clave son TSqlStatement y ExecuteStatement.Por último, agregue la sección del procesamiento posterior en lugar del comentario “Agregar el procesamiento posterior aquí”:
// Declare a SqlCmd variables. // // CompletedBatches variable - defines the name of the table in tempdb that tracks all // the completed batches. The temporary table's name has the target database name and // a GUID embedded in it so that: // * Multiple deployment scripts targeting different DBs on the same server // * Failed deployments with old tables do not conflict with more recent deployments // // TotalBatchCount variable - the total number of batches surrounded by if statements. Using this // variable pre/post deployment scripts can also use the CompletedBatches table to make their // script rerunnable if there is an error during execution StringBuilder sqlcmdVars = new StringBuilder(); sqlcmdVars.AppendFormat(CultureInfo.InvariantCulture, CompletedBatchesSqlCmd, context.Options.TargetDatabaseName, Guid.NewGuid().ToString("D")); sqlcmdVars.AppendLine(); sqlcmdVars.AppendFormat(CultureInfo.InvariantCulture, TotalBatchCountSqlCmd, batchId); DeploymentScriptStep completedBatchesSetVarStep = new DeploymentScriptStep(sqlcmdVars.ToString()); base.AddBefore(context.PlanHandle, beforePreDeploy, completedBatchesSetVarStep); // Create the temporary table we use to track the work that we are doing DeploymentScriptStep createStatusTableStep = new DeploymentScriptStep(CreateCompletedBatchesTable); base.AddBefore(context.PlanHandle, beforePreDeploy, createStatusTableStep);Si el procesamiento detecta uno o varios pasos que rodeamos con una instrucción condicional, debemos agregar instrucciones al script de implementación para definir variables SQLCMD. Las variables son las siguientes:
CompletedBatchescontiene un nombre único para la tabla temporal que usa el script de implementación para realizar un seguimiento de los lotes que se completan correctamente cuando se ejecuta el script.TotalBatchCountcontiene el número total de lotes en el script de implementación.
Otros tipos, propiedades y métodos de interés son:
StringBuilder, DeploymentScriptStep yAddBefore.A continuación, define los métodos del asistente llamados por este método.
Adición de los métodos auxiliares
Se deben definir varios métodos auxiliares. Los métodos importantes son:
Método Description CreateExecuteSQLDefina el método CreateExecuteSQL para envolver una instrucción proporcionada con una declaración EXECsp_executesql. Los tipos, métodos, y propiedades clave incluyen los siguientes componentes de API de DacFx: ExecuteStatement, ExecutableProcedureReference, SchemaObjectName, ProcedureReferencey ExecuteParameter.CreateCompletedBatchesNameDefine el método CreateCompletedBatchesName. Este método crea el nombre que se inserta en la tabla temporal para un lote. Entre los tipos de clave, los métodos y las propiedades se incluyen los siguientes componentes de la API de DacFx: SchemaObjectName. IsStatementEscapedDefine el método IsStatementEscaped. Este método determina si el tipo de elemento de modelo requiere que la instrucción se encapsula en una EXECsp_executesqlinstrucción antes de que se pueda incluir dentro de unaIFinstrucción . Entre las propiedades, métodos y tipos de clave se encuentran los siguientes componentes de API de DacFx: TSqlObject.ObjectType, ModelTypeClass y la propiedad TypeClass de los tipos de modelo siguientes: Schema, Procedure, View, TableValuedFunction, ScalarFunction, DatabaseDdlTrigger, DmlTrigger y ServerDdlTrigger.CreateBatchCompleteInsertDefine el método CreateBatchCompleteInsert. Este método crea la INSERTinstrucción que se agrega al script de implementación para realizar un seguimiento del progreso de la ejecución del script. Entre las propiedades, métodos y tipos clave se encuentran los siguientes componentes de API de DacFx: InsertStatement, NamedTableReference, ColumnReferenceExpression, ValuesInsertSource y RowValue.CreateIfNotExecutedStatementDefine el método CreateIfNotExecutedStatement. Este método genera una IFinstrucción que comprueba si la tabla de ejecución temporal de batche indica que este lote ya se ha ejecutado. Los tipos de clave, los métodos y las propiedades incluyen: IfStatement, ExistsPredicate, ScalarSubquery, NamedTableReference, WhereClause, ColumnReferenceExpression, IntegerLiteral, BooleanComparisonExpression y BooleanNotExpression.GetStepInfoDefina el método GetStepInfo. Este método extrae la información sobre el elemento modelo usado para crear el script del paso, además del nombre del paso. Los tipos y métodos de interés incluyen: DeploymentPlanContributorContext, DeploymentScriptDomStep, TSqlObject, CreateElementStep, AlterElementStep y DropElementStep. GetElementNameCrea un nombre con formato para un TSqlObject.
Agregue el código siguiente para definir los métodos del asistente:
/// <summary> /// The CreateExecuteSql method "wraps" the provided statement script in an "sp_executesql" statement /// Examples of statements that must be so wrapped include: stored procedures, views, and functions /// </summary> private static ExecuteStatement CreateExecuteSql(string statementScript) { // define a new Exec statement ExecuteStatement executeSp = new ExecuteStatement(); ExecutableProcedureReference spExecute = new ExecutableProcedureReference(); executeSp.ExecuteSpecification = new ExecuteSpecification { ExecutableEntity = spExecute }; // define the name of the procedure that you want to execute, in this case sp_executesql SchemaObjectName procName = new SchemaObjectName(); procName.Identifiers.Add(CreateIdentifier("sp_executesql", QuoteType.NotQuoted)); ProcedureReference procRef = new ProcedureReference { Name = procName }; spExecute.ProcedureReference = new ProcedureReferenceName { ProcedureReference = procRef }; // add the script parameter, constructed from the provided statement script ExecuteParameter scriptParam = new ExecuteParameter(); spExecute.Parameters.Add(scriptParam); scriptParam.ParameterValue = new StringLiteral { Value = statementScript }; scriptParam.Variable = new VariableReference { Name = "@stmt" }; return executeSp; } /// <summary> /// The CreateIdentifier method returns a Identifier with the specified value and quoting type /// </summary> private static Identifier CreateIdentifier(string value, QuoteType quoteType) { return new Identifier { Value = value, QuoteType = quoteType }; } /// <summary> /// The CreateCompletedBatchesName method creates the name that is inserted /// into the temporary table for a batch. /// </summary> private static SchemaObjectName CreateCompletedBatchesName() { SchemaObjectName name = new SchemaObjectName(); name.Identifiers.Add(CreateIdentifier("tempdb", QuoteType.SquareBracket)); name.Identifiers.Add(CreateIdentifier("dbo", QuoteType.SquareBracket)); name.Identifiers.Add(CreateIdentifier(CompletedBatchesVariable, QuoteType.SquareBracket)); return name; } /// <summary> /// Helper method that determines whether the specified statement needs to /// be escaped /// </summary> /// <param name="sqlObject"></param> /// <returns></returns> private static bool IsStatementEscaped(TSqlObject sqlObject) { HashSet<ModelTypeClass> escapedTypes = new HashSet<ModelTypeClass> { Schema.TypeClass, Procedure.TypeClass, View.TypeClass, TableValuedFunction.TypeClass, ScalarFunction.TypeClass, DatabaseDdlTrigger.TypeClass, DmlTrigger.TypeClass, ServerDdlTrigger.TypeClass }; return escapedTypes.Contains(sqlObject.ObjectType); } /// <summary> /// Helper method that creates an INSERT statement to track a batch being completed /// </summary> /// <param name="batchId"></param> /// <param name="batchDescription"></param> /// <returns></returns> private static InsertStatement CreateBatchCompleteInsert(int batchId, string batchDescription) { InsertStatement insert = new InsertStatement(); NamedTableReference batchesCompleted = new NamedTableReference(); insert.InsertSpecification = new InsertSpecification(); insert.InsertSpecification.Target = batchesCompleted; batchesCompleted.SchemaObject = CreateCompletedBatchesName(); // Build the columns inserted into ColumnReferenceExpression batchIdColumn = new ColumnReferenceExpression(); batchIdColumn.MultiPartIdentifier = new MultiPartIdentifier(); batchIdColumn.MultiPartIdentifier.Identifiers.Add(CreateIdentifier(BatchIdColumnName, QuoteType.NotQuoted)); ColumnReferenceExpression descriptionColumn = new ColumnReferenceExpression(); descriptionColumn.MultiPartIdentifier = new MultiPartIdentifier(); descriptionColumn.MultiPartIdentifier.Identifiers.Add(CreateIdentifier(DescriptionColumnName, QuoteType.NotQuoted)); insert.InsertSpecification.Columns.Add(batchIdColumn); insert.InsertSpecification.Columns.Add(descriptionColumn); // Build the values inserted ValuesInsertSource valueSource = new ValuesInsertSource(); insert.InsertSpecification.InsertSource = valueSource; RowValue values = new RowValue(); values.ColumnValues.Add(new IntegerLiteral { Value = batchId.ToString() }); values.ColumnValues.Add(new StringLiteral { Value = batchDescription }); valueSource.RowValues.Add(values); return insert; } /// <summary> /// This is a helper method that generates an if statement that checks the batches executed /// table to see if the current batch has been executed. The if statement looks like this /// /// if not exists(select 1 from [tempdb].[dbo].[$(CompletedBatches)] /// where BatchId = batchId) /// begin /// end /// </summary> /// <param name="batchId"></param> /// <returns></returns> private static IfStatement CreateIfNotExecutedStatement(int batchId) { // Create the exists/select statement ExistsPredicate existsExp = new ExistsPredicate(); ScalarSubquery subQuery = new ScalarSubquery(); existsExp.Subquery = subQuery; subQuery.QueryExpression = new QuerySpecification { SelectElements = { new SelectScalarExpression { Expression = new IntegerLiteral { Value ="1" } } }, FromClause = new FromClause { TableReferences = { new NamedTableReference() { SchemaObject = CreateCompletedBatchesName() } } }, WhereClause = new WhereClause { SearchCondition = new BooleanComparisonExpression { ComparisonType = BooleanComparisonType.Equals, FirstExpression = new ColumnReferenceExpression { MultiPartIdentifier = new MultiPartIdentifier { Identifiers = { CreateIdentifier(BatchIdColumnName, QuoteType.SquareBracket) } } }, SecondExpression = new IntegerLiteral { Value = batchId.ToString() } } } }; // Put together the rest of the statement IfStatement ifNotExists = new IfStatement { Predicate = new BooleanNotExpression { Expression = existsExp } }; return ifNotExists; } /// <summary> /// Helper method that generates a useful description of the step. /// </summary> private static void GetStepInfo( DeploymentScriptDomStep domStep, out string stepDescription, out TSqlObject element) { element = null; // figure out what type of step we've got, and retrieve // either the source or target element. if (domStep is CreateElementStep) { element = ((CreateElementStep)domStep).SourceElement; } else if (domStep is AlterElementStep) { element = ((AlterElementStep)domStep).SourceElement; } else if (domStep is DropElementStep) { element = ((DropElementStep)domStep).TargetElement; } // construct the step description by concatenating the type and the fully qualified // name of the associated element. string stepTypeName = domStep.GetType().Name; if (element != null) { string elementName = GetElementName(element); stepDescription = string.Format(CultureInfo.InvariantCulture, "{0} {1}", stepTypeName, elementName); } else { // if the step has no associated element, just use the step type as the description stepDescription = stepTypeName; } } private static string GetElementName(TSqlObject element) { StringBuilder name = new StringBuilder(); if (element.Name.HasExternalParts) { foreach (string part in element.Name.ExternalParts) { if (name.Length > 0) { name.Append('.'); } name.AppendFormat("[{0}]", part); } } foreach (string part in element.Name.Parts) { if (name.Length > 0) { name.Append('.'); } name.AppendFormat("[{0}]", part); } return name.ToString(); }Guarde los cambios de SqlRestartableScriptContributor.cs.
A continuación, compile la biblioteca de clases.
Firmar y construir el ensamblaje
En el menú Proyecto, seleccione MyOtherDeploymentContributor Properties (Propiedades de MyOtherDeploymentContributor).
Seleccione la pestaña Firma .
Seleccione Firmar el ensamblado.
En Elegir un archivo de clave de nombre seguro, seleccione <Nuevo>.
En el cuadro de diálogo Crear clave de nombre seguro , en el Nombre del archivo clave, escriba MyRefKey.
(opcional) Puede especificar una contraseña para el archivo de clave de nombre seguro.
Selecciona Aceptar.
En el menú Archivo, seleccione Guardar todo.
En el menú Compilar, seleccione Compilar solución.
A continuación, debe instalar el ensamblado para que se cargue al implementar proyectos SQL.
Instalación de un colaborador de implementación
Para instalar un colaborador de implementación, debe copiar el ensamblado y el archivo asociado .pdb a la carpeta Extensiones.
Instala el ensamblado MyOtherDeploymentContributor
A continuación, copie la información del ensamblado en el directorio de Extensiones. Cuando se inicia Visual Studio 2022, identifica las extensiones del
%ProgramFiles%\Microsoft Visual Studio\2022\Enterprise\Common7\IDE\Extensions\Microsoft\SQLDB\DACdirectorio y los subdirectorios y los pone a disposición para su uso.Copie el archivo de ensamblado MyOtherDeploymentContributor.dll del directorio de salida en el
%ProgramFiles%\Microsoft Visual Studio\2022\Enterprise\Common7\IDE\Extensions\Microsoft\SQLDB\DACdirectorio . De forma predeterminada, la ruta de acceso del archivo compilado.dllesYourSolutionPath\YourProjectPath\bin\DebugoYourSolutionPath\YourProjectPath\bin\Release.
Ejecuta o prueba tu componente de implementación
Para ejecutar o comprobar su colaborador de implementación, debe realizar las siguientes tareas:
Agregue propiedades al
.sqlprojarchivo que planea compilar.Implemente el proyecto de base de datos utilizando MSBuild y proporcionando los parámetros apropiados.
Agregar propiedades al archivo del proyecto SQL (.sqlproj)
Debe actualizar siempre el archivo de proyecto SQL para especificar el identificador de los colaboradores que desee ejecutar. Puede actualizar el proyecto SQL de una de estas dos maneras:
Puede modificar manualmente el
.sqlprojarchivo para agregar los argumentos necesarios. Puede optar por hacerlo si el colaborador no tiene ningún argumento de colaborador necesario para la configuración o si no pretende reutilizar el colaborador de compilación en un gran número de proyectos. Si elige esta opción, agregue las siguientes instrucciones al archivo.sqlprojdespués del primer nodo Import del archivo.<PropertyGroup> <DeploymentContributors> $(DeploymentContributors); MyOtherDeploymentContributor.RestartableScriptContributor </DeploymentContributors> </PropertyGroup>El segundo método es crear un archivo de destino que contenga los argumentos de colaborador necesarios. Esto resulta útil si usa el mismo colaborador para varios proyectos y tiene argumentos de colaborador necesarios, ya que incluye los valores predeterminados. En este caso, cree un archivo de destino en la ruta de extensiones MSBuild:
Navegue a
%ProgramFiles%\MSBuild.Cree una carpeta nueva “MyContributors” donde se almacenan los archivos de destino.
Cree un archivo nuevo “MyContributors.targets” en este directorio, agréguele el siguiente texto y guarde el archivo:
<?xml version="1.0" encoding="utf-8"?> <Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> <PropertyGroup> <DeploymentContributors>$(DeploymentContributors);MyOtherDeploymentContributor.RestartableScriptContributor</DeploymentContributors> </PropertyGroup> </Project>Dentro del archivo
.sqlprojpara cualquier proyecto en el que desee ejecutar scripts adicionales, importe el archivo de targets agregando la siguiente instrucción al archivo.sqlprojdespués del nodo <Import Project="$(MSBuildExtensionsPath)\Microsoft\VisualStudio\v$(VisualStudioVersion)\SSDT\Microsoft.Data.Tools.Schema.SqlTasks.targets" /> en el archivo:<Import Project="$(MSBuildExtensionsPath)\MyContributors\MyContributors.targets " />
Después de haber seguido uno de estos métodos, puede usar MSBuild con el fin de pasar los parámetros para compilaciones de línea de comandos.
Nota
Debe actualizar siempre la propiedad “DeploymentContributors” para especificar el identificador de colaborador. Es el mismo identificador utilizado en el atributo “ExportDeploymentPlanModifier” en el archivo de origen del colaborador. Sin esto, el componente no se ejecuta al construir el proyecto. Únicamente es necesario actualizar la propiedad “ContributorArguments” si tiene argumentos necesarios para ejecutar su colaborador.
Implementación del proyecto de base de datos
El proyecto se puede publicar o implementar de manera habitual en Visual Studio. Abra una solución que contenga el proyecto SQL y elija la opción Publicar... en el menú contextual del proyecto, haga clic con el botón derecho, o use F5 para una implementación de depuración en LocalDB. En este ejemplo utilizamos el diálogo “Publicar…” para generar un script de implementación.
Abra Visual Studio y abra la solución que contiene el proyecto de SQL.
Haga clic con el botón derecho en el proyecto del Explorador de soluciones y elija la opción Publicar… .
Establezca el nombre del servidor y de la base de datos en los que vaya a publicar.
Elija Generar script de las opciones en la parte inferior del diálogo. Esta acción creará un script que se puede utilizar para la implementación. Podemos examinar este script para comprobar que nuestras
IFinstrucciones se han agregado para que el script se pueda reiniciar.Examine el script de implementación resultante. Justo antes de la sección con la etiqueta “Plantilla de script anterior a la implementación”, debería ver algo similar a la siguiente sintaxis Transact-SQL:
:setvar CompletedBatches __completedBatches_CompareProjectDB_cd1e348a-8f92-44e0-9a96-d25d65900fca :setvar TotalBatchCount 17 GO if OBJECT_ID(N'tempdb.dbo.$(CompletedBatches)', N'U') is null BEGIN USE tempdb; CREATE TABLE [dbo].[$(CompletedBatches)] ( BatchId INT PRIMARY KEY, Description NVARCHAR(300) ); USE [$(DatabaseName)]; ENDMás adelante en el script de implementación, alrededor de cada lote, verá una
IFdeclaración que rodea la declaración original. Por ejemplo, el siguiente script de T-SQL podría aparecer para unaCREATE SCHEMAinstrucción :IF NOT EXISTS (SELECT 1 FROM [tempdb].[dbo].[$(CompletedBatches)] WHERE [BatchId] = 0) BEGIN EXECUTE sp_executesql @stmt = N'CREATE SCHEMA [Sales] AUTHORIZATION [dbo]'; SET NOCOUNT ON; INSERT [tempdb].[dbo].[$(CompletedBatches)] (BatchId, Description) VALUES (0, N'CreateElementStep Sales batch 0'); SET NOCOUNT OFF; ENDCREATE SCHEMAes una de las instrucciones que deben estar incluidas dentro de una instrucciónEXECUTEsp_executesqldentro de la instrucciónIF. Instrucciones comoCREATE TABLEno requieren laEXECUTEsp_executesqlinstrucción y se parece al ejemplo siguiente:IF NOT EXISTS (SELECT 1 FROM [tempdb].[dbo].[$(CompletedBatches)] WHERE [BatchId] = 1) BEGIN CREATE TABLE [Sales].[Customer] ( [CustomerID] INT IDENTITY (1, 1) NOT NULL, [CustomerName] NVARCHAR (40) NOT NULL, [YTDOrders] INT NOT NULL, [YTDSales] INT NOT NULL ); SET NOCOUNT ON; INSERT [tempdb].[dbo].[$(CompletedBatches)] (BatchId, Description) VALUES (1, N'CreateElementStep Sales.Customer batch 0'); SET NOCOUNT OFF; ENDNota
Si implementa un proyecto de base de datos idéntico a la base de datos de destino, el informe resultante no es muy significativo. Para resultados más significativos, implemente los cambios en una base de datos o implemente una nueva base de datos.
Implementación de la línea de comandos mediante el archivo dacpac generado
El artefacto de salida de una compilación de proyecto SQL es un .dacpac archivo. Se puede usar un .dacpac archivo para implementar el esquema desde la línea de comandos y que puede habilitar la implementación desde una máquina diferente, como una máquina de compilación. SqlPackage es un programa de línea de comandos con una gama completa de opciones que permite a los usuarios implementar un dacpac o generar un script de implementación, entre otras acciones. Para obtener más información, vea SqlPackage.
Nota
Para implementar correctamente dacpacs compilados a partir de proyectos con la propiedad DeploymentContributors definida, los archivos DLL que contienen los colaboradores de implementación deben instalarse en la máquina que se usa. Esto es así porque se han marcado como necesarios para que la implementación se complete correctamente.
Para evitar este requisito, excluya el colaborador de implementación del .sqlproj archivo. En su lugar, especifique que los colaboradores se ejecuten durante la implementación mediante SqlPackage con el parámetro AdditionalDeploymentContributors. Esto es útil si solo desea utilizar un colaborador para circunstancias especiales, como la implementación en un servidor concreto.
Contenido relacionado
- Personalización de la compilación e implementación de bases de datos mediante colaboradores de compilación e implementación
- Tutorial: Ampliación de la compilación del proyecto de base de datos para generar estadísticas de modelo
- Tutorial: Ampliación de la implementación del proyecto de base de datos para analizar el plan de implementación