Condividi tramite


Procedura dettagliata: estendere la distribuzione del progetto di database per modificare il piano di distribuzione

È possibile creare collaboratori alla distribuzione per eseguire azioni personalizzate quando si distribuisce un progetto di database. È possibile creare un DeploymentPlanModifier o un DeploymentPlanExecutor. Utilizzare un DeploymentPlanModifier per modificare il piano prima che venga eseguito e un DeploymentPlanExecutor per eseguire operazioni mentre il piano viene eseguito. In questa procedura dettagliata si creerà un DeploymentPlanModifier denominato SqlRestartableScriptContributor che aggiunge istruzioni IF ai batch nello script di distribuzione per consentire la riesecuzione dello script fino al completamento, in caso si verifichi un errore durante l'esecuzione.

In questa procedura dettagliata si completeranno le seguenti attività principali:

  • Creare il tipo DeploymentPlanModifier di collaboratore alla distribuzione

  • Installare il collaboratore alla distribuzione

  • Testare il collaboratore alla distribuzione

Prerequisiti

Per completare la procedura dettagliata, è necessario disporre dei componenti seguenti:

  • Visual Studio 2010 Premium o Visual Studio 2010 Ultimate installato nel computer.

  • Un progetto di database contenente oggetti di database.

  • Un'istanza di SQL Server alla quale è possibile distribuire un progetto di database

Nota

Questa procedura dettagliata è destinata a utenti che hanno già familiarità con le funzionalità di database di Visual Studio. È inoltre necessario conoscere i concetti di base di Visual Studio, ad esempio come creare una libreria di classi e come utilizzare l'editor di codice per aggiungere codice a una classe.

Creare un collaboratore alla distribuzione

Per creare un collaboratore alla distribuzione, è necessario effettuare le attività seguenti:

  • Creare un progetto Libreria di classi e aggiungere riferimenti obbligatori

  • Definire una classe denominata SqlRestartableScriptContributor che eredita da DeploymentPlanModifier

  • Eseguire l'override del metodo OnExecute

  • Aggiungere metodi di supporto privati

  • Compilare l'assembly risultante

Per creare un progetto Libreria di classi

  1. Creare un progetto Libreria di classi di Visual C# or Visual Basic denominato MyOtherDeploymentContributor.

  2. In Esplora soluzioni fare clic con il pulsante destro del mouse sul progetto, quindi scegliere Aggiungi riferimento.

  3. Fare clic sulla scheda .NET.

  4. Evidenziare le voci Microsoft.Data.Schema, Microsoft.Data.Schema.Sql, Microsoft.Data.Schema.ScriptDom e Microsoft.Data.Schema.ScriptDom.Sql e fare clic su OK.

    Iniziare quindi ad aggiungere codice alla classe.

Per definire la classe SqlRestartableScriptContributor

  1. Nell'editor di codice aggiornare il file class1.cs affinché corrisponda alle seguenti istruzioni using:

    using System;
    using System.Collections.Generic;
    using System.Text;
    using Microsoft.Data.Schema.Build;
    using Microsoft.Data.Schema.ScriptDom.Sql;
    using Microsoft.Data.Schema.SchemaModel;
    using System.Globalization;
    using Microsoft.Data.Schema.ScriptDom;
    using Microsoft.Data.Schema.Extensibility;
    using Microsoft.Data.Schema.Sql;
    using Microsoft.Data.Schema.Sql.Build;
    using Microsoft.Data.Schema.Sql.SchemaModel;
    
    Imports System
    Imports System.Collections.Generic
    Imports System.Text
    Imports Microsoft.Data.Schema.Build
    Imports Microsoft.Data.Schema.ScriptDom.Sql
    Imports Microsoft.Data.Schema.SchemaModel
    Imports System.Globalization
    Imports Microsoft.Data.Schema.ScriptDom
    Imports Microsoft.Data.Schema.Extensibility
    Imports Microsoft.Data.Schema.Sql
    Imports Microsoft.Data.Schema.Sql.Build
    Imports Microsoft.Data.Schema.Sql.SchemaModel
    
  2. Aggiornare la definizione della classe in modo che corrisponda all'esempio seguente:

            /// <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>
        [DatabaseSchemaProviderCompatibility(typeof(SqlDatabaseSchemaProvider))]
        class SqlRestartableScriptContributor : DeploymentPlanModifier
        {
        }
    
    ''' <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> 
    <DatabaseSchemaProviderCompatibility(GetType(SqlDatabaseSchemaProvider))> _
    Class SqlRestartableScriptContributor
        Inherits DeploymentPlanModifier
    End Class
    

    A questo punto è stato definito il collaboratore alla compilazione che eredita da DeploymentPlanModifier. È stato utilizzato l'attributo DatabaseSchemaProviderCompatibilityAttribute per indicare che questo collaboratore è compatibile con qualsiasi provider dello schema di database che eredita da SqlDatabaseSchemaProvider.

  3. Aggiungere le seguenti dichiarazioni di membro:

            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
    ";
            private const string DropCompletedBatchesTable = @"drop table [tempdb].[dbo].[" + CompletedBatchesVariable + "]";
    
        Private Const BatchIdColumnName As String = "BatchId"
        Private Const DescriptionColumnName As String = "Description"
    
        Private Const CompletedBatchesVariableName As String = "CompletedBatches"
        Private Const CompletedBatchesVariable As String = "$(CompletedBatches)"
        Private Const CompletedBatchesSqlCmd As String = ":setvar " & CompletedBatchesVariableName & " __completedBatches_{0}_{1}"
        Private Const TotalBatchCountSqlCmd As String = ":setvar TotalBatchCount {0}"
        Private Const CreateCompletedBatchesTable As String = vbCr & vbLf & "if OBJECT_ID(N'tempdb.dbo." & CompletedBatchesVariable & "', N'U') is null" & vbCr & vbLf & "begin" & vbCr & vbLf & vbTab & "use tempdb" & vbTab & vbCr & vbLf & vbTab & "create table [dbo].[$(CompletedBatches)]" & vbCr & vbLf & vbTab & "(" & vbCr & vbLf & vbTab & vbTab & "BatchId int primary key," & vbCr & vbLf & vbTab & vbTab & "Description nvarchar(300)" & vbCr & vbLf & vbTab & ")" & vbCr & vbLf & vbTab & "use [$(DatabaseName)]" & vbTab & vbCr & vbLf & "end" & vbCr & vbLf
        Private Const DropCompletedBatchesTable As String = "drop table [tempdb].[dbo].[" & CompletedBatchesVariable & "]"
    

    Eseguire quindi l'override del metodo OnExecute per aggiungere il codice che si desidera eseguire quando viene distribuito un progetto di database.

Per eseguire l'override di OnExecute

  1. Aggiungere il metodo riportato di seguito alla classe 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
            }
    
        ''' <summary> 
        ''' You override the OnExecute method to do the real work of the contributor. 
        ''' </summary> 
        ''' <param name="context"></param> 
        Protected Overloads Overrides Sub OnExecute(ByVal context As DeploymentPlanContributorContext)
            ' Replace this with the method body
        End Sub
    

    Eseguire l'override del metodo OnExecute dalla classe di base, DeploymentPlanContributor, che è la classe di base sia per DeploymentPlanModifier che per DeploymentPlanExecutor. Al metodo OnExecute viene passato un oggetto DeploymentPlanContributorContext che fornisce l'accesso a qualsiasi argomento specificato, al modello del database di origine e di destinazione, alle proprietà di compilazione e ai file di estensione. In questo esempio si otterranno il piano di distribuzione e il nome del database di destinazione.

  2. Ora si aggiungeranno gli elementi iniziali di un corpo al metodo 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);
    
            ' Obtain the first step in the Plan from the provided context 
            Dim nextStep As DeploymentStep = context.PlanHandle.Head
            Dim batchId As Integer = 0
            Dim beforePreDeploy As BeginPreDeploymentScriptStep = Nothing
    
            ' Loop through all steps in the deployment plan 
            While nextStep IsNot Nothing
                ' Increment the step pointer, saving both the current and next steps 
                Dim currentStep As DeploymentStep = nextStep
                nextStep = currentStep.[Next]
    
                '  Add additional step processing here
            End While
    
            ' if we found steps that required processing, set up a temporary table to track the work that you are doing 
            If beforePreDeploy IsNot Nothing Then
                '  Add additional post-processing here
            End If
    
            ' Cleanup and drop the table 
            Dim dropStep As New DeploymentScriptStep(DropCompletedBatchesTable)
            MyBase.AddAfter(context.PlanHandle, context.PlanHandle.Tail, dropStep)
    

    In questo codice si definiscono alcune variabili locali e si configura il ciclo che gestisce l'elaborazione di tutti i passaggi nel piano di distribuzione. Dopo il completamento del ciclo, si dovrà procedere alla post-elaborazione e si rilascerà quindi la tabella temporanea creata durante la distribuzione per tenere traccia dello stato di avanzamento mentre il piano veniva eseguito. I tipi principali, in questo caso, sono: DeploymentStep e DeploymentScriptStep. Un metodo principale è AddAfter .

  3. Si aggiungerà quindi l'elaborazione dettagliata aggiuntiva per sostituire il commento "Add additional step processing here":

                // Look for steps that mark the pre/post deployment scripts
                // These steps will always be 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 begining 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 will be enclosed in an if statement that will check the
                // table to ensure that the batch has not already been executed
                IModelElement element;
                string stepDescription;
                GetStepInfo(context, domStep, out stepDescription, out element);
                int batchCount = script.Batches.Count;
    
                for (int batchIndex = 0; batchIndex < batchCount; batchIndex++)
                {
                    // Add batch processing here
                }
    
                ' Look for steps that mark the pre/post deployment scripts 
                ' These steps will always be in the deployment plan even if the 
                ' user's project does not have a pre/post deployment script 
                If TypeOf currentStep Is BeginPreDeploymentScriptStep Then
                    ' This step marks the begining of the predeployment script. 
                    ' Save the step and move on. 
                    beforePreDeploy = DirectCast(currentStep, BeginPreDeploymentScriptStep)
                    Continue While
                End If
                If TypeOf currentStep Is BeginPostDeploymentScriptStep Then
                    ' This is the step that marks the beginning of the post deployment script. 
                    ' We do not continue processing after this point. 
                    Exit While
                End If
                If TypeOf currentStep Is SqlPrintStep Then
                    ' We do not need to put if statements around these 
                    Continue While
                End If
    
                ' if we have not yet found the beginning of the pre-deployment script steps, 
                ' skip to the next step. 
                If beforePreDeploy Is Nothing Then
                    ' We only surround the "main" statement block with conditional 
                    ' statements 
                    Continue While
                End If
    
                ' Determine if this is a step that we need to surround with a conditional statement 
                Dim domStep As DeploymentScriptDomStep = TryCast(currentStep, DeploymentScriptDomStep)
                If domStep Is Nothing Then
                    ' This step is not a step that we know how to modify, 
                    ' so skip to the next step. 
                    Continue While
                End If
    
                Dim script As TSqlScript = TryCast(domStep.Script, TSqlScript)
                If script Is Nothing Then
                    ' The script dom step does not have a script with batches - skip 
                    Continue While
                End If
    
                ' Loop through all the batches in the script for this step. All the statements 
                ' in the batch will be enclosed in an if statement that will check the 
                ' table to ensure that the batch has not already been executed 
                Dim element As IModelElement = Nothing
                Dim stepDescription As String = ""
                GetStepInfo(context, domStep, stepDescription, element)
                Dim batchCount As Integer = script.Batches.Count
    
                For batchIndex As Integer = 0 To batchCount - 1
                    ' Add batch processing here
                Next
    

    I commenti del codice descrivono l'elaborazione. A livello generale, questo codice cerca i passaggi di interesse, ignorando gli altri e arrestandosi quando si raggiunge l'inizio dei passaggi post-distribuzione. Se il passaggio contiene istruzioni che devono essere racchiusi con istruzioni condizionali, si eseguirà un'elaborazione aggiuntiva. Tipi, metodi e proprietà principali includono i seguenti: BeginPreDeploymentScriptStep, BeginPostDeploymentScriptStep, IModelElement, TSqlScript, Script, DeploymentScriptDomStep e SqlPrintStep.

  4. Aggiungere il codice dell'elaborazione batch sostituendo il commento "Add batch processing here":

                        // Create the if statement that will contain 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++;
    
                    ' Create the if statement that will contain the batch's contents 
                    Dim ifBatchNotExecutedStatement As IfStatement = CreateIfNotExecutedStatement(batchId)
                    Dim statementBlock As New BeginEndBlockStatement()
                    ifBatchNotExecutedStatement.ThenStatement = statementBlock
                    statementBlock.StatementList = New StatementList()
    
                    Dim batch As TSqlBatch = script.Batches(batchIndex)
                    Dim statementCount As Integer = 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 statementIndex As Integer = 0 To statementCount - 1
                        ' Add additional statement processing here
                    Next
    
                    ' 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 
                    Dim batchDescription As String = String.Format(CultureInfo.InvariantCulture, "{0} batch {1}", stepDescription, batchIndex)
    
                    Dim noCountOff As New PredicateSetStatement()
                    noCountOff.IsOn = False
                    noCountOff.Options = SetOptions.NoCount
    
                    Dim noCountOn As New PredicateSetStatement()
                    noCountOn.IsOn = True
                    noCountOn.Options = SetOptions.NoCount
                    Dim batchCompleteInsert As InsertStatement = 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 += 1
    

    Questo codice crea un'istruzione IF insieme a un blocco BEGIN/END. Si eseguirà quindi l'elaborazione aggiuntiva sulle istruzioni contenute nel batch. Una volta completato, si aggiungerà un'istruzione INSERT per includer informazioni nella tabella temporanea che tiene traccia dello stato di avanzamento dell'esecuzione degli script. Infine, aggiornare il batch, sostituendo le istruzioni solitamente presenti con la nuova istruzione IF che contiene tali istruzioni.

    Tipi, metodi e proprietà principali includono:IfStatement, BeginEndBlockStatement, StatementList, TSqlBatch, PredicateSetStatement, SetOptions e InsertStatement.

  5. Aggiungere il corpo del ciclo di elaborazione dell'istruzione. Sostituire il commento "Add additional statement processing here":

                            TSqlStatement smnt = batch.Statements[statementIndex];
    
                            if (IsStatementEscaped(element))
                            {
                                // "escape" this statement by embedding it in a sp_executesql statement
                                string statementScript = null;
                                domStep.ScriptGenerator.GenerateScript(smnt, out statementScript);
                                ExecuteStatement spExecuteSql = CreateExecuteSql(statementScript);
                                smnt = spExecuteSql;
                            }
    
                            statementBlock.StatementList.Statements.Add(smnt);
    
                        Dim smnt As TSqlStatement = batch.Statements(statementIndex)
    
                        If IsStatementEscaped(element) Then
                            ' "escape" this statement by embedding it in a sp_executesql statement 
                            Dim statementScript As String = Nothing
                            domStep.ScriptGenerator.GenerateScript(smnt, statementScript)
                            Dim spExecuteSql As ExecuteStatement = CreateExecuteSql(statementScript)
                            smnt = spExecuteSql
                        End If
    
                        statementBlock.StatementList.Statements.Add(smnt)
    

    Per ogni istruzione nel batch, se l'istruzione è di un tipo di cui deve essere eseguito il wrapping con l'istruzione sp_executesql, modificare di conseguenza l'istruzione. Il codice aggiunge quindi l'istruzione all'elenco di istruzioni per il blocco BEGIN/END creato. I tipi, i metodi e le proprietà principali includono TSqlStatement e ExecuteStatement.

  6. Si aggiungerà infine la sezione di post-elaborazione al posto del commento "Add additional post-processing here":

                    // Declare a SqlCmd variables.
                    //
                    // CompletedBatches variable - defines the name of the table in tempdb that will track
                    // 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 will use to track the work that we are doing
                    DeploymentScriptStep createStatusTableStep = new DeploymentScriptStep(CreateCompletedBatchesTable);
                    base.AddBefore(context.PlanHandle, beforePreDeploy, createStatusTableStep);
    
                ' Declare a SqlCmd variables. 
                ' 
                ' CompletedBatches variable - defines the name of the table in tempdb that will track 
                ' 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 
                Dim sqlcmdVars As New StringBuilder()
                sqlcmdVars.AppendFormat(CultureInfo.InvariantCulture, CompletedBatchesSqlCmd, context.Options.TargetDatabaseName, Guid.NewGuid().ToString("D"))
                sqlcmdVars.AppendLine()
                sqlcmdVars.AppendFormat(CultureInfo.InvariantCulture, TotalBatchCountSqlCmd, batchId)
    
                Dim completedBatchesSetVarStep As New DeploymentScriptStep(sqlcmdVars.ToString())
                MyBase.AddBefore(context.PlanHandle, beforePreDeploy, completedBatchesSetVarStep)
    
                ' Create the temporary table we will use to track the work that we are doing 
                Dim createStatusTableStep As New DeploymentScriptStep(CreateCompletedBatchesTable)
                MyBase.AddBefore(context.PlanHandle, beforePreDeploy, createStatusTableStep)
    

    Se durante l'elaborazione vengono rilevati uno o più passaggi racchiusi con un'istruzione condizionale, si dovranno aggiungere istruzioni allo script di distribuzione per definire variabili SQLCMD. La prima variabile, CompletedBatches, contiene un nome univoco per la tabella temporanea che lo script di distribuzione utilizza per tenere traccia dei batch completati correttamente quando viene eseguito lo script. La seconda variabile, TotalBatchCount, contiene il numero complessivo di batch nello script di distribuzione.

    Tipi, proprietà e metodi di interesse aggiuntivi includono:

    StringBuilder, DeploymentScriptStep e AddBefore.

    Si definiranno quindi i metodi di supporto chiamati da questo metodo.

Per aggiungere il metodo CreateExecuteSql

  • Aggiungere il codice seguente per definire il metodo CreateExecuteSQL che racchiude un'istruzione fornita con un'istruzione EXEC sp_executesql:

            /// <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>
            /// <param name="string"></param>
            /// <returns></returns>
            private static ExecuteStatement CreateExecuteSql(string statementScript)
            {
                // define a new Exec statement
                ExecuteStatement executeSp = new ExecuteStatement();
                ExecutableProcedureReference spExecute = new ExecutableProcedureReference();
                executeSp.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();
                procRef.Name = procName;
                spExecute.ProcedureReference = procRef;
    
                // add the script parameter, constructed from the provided statement script
                ExecuteParameter scriptParam = new ExecuteParameter();
                spExecute.Parameters.Add(scriptParam);
                scriptParam.ParameterValue = CreateLiteral(statementScript, LiteralType.UnicodeStringLiteral);
                scriptParam.Variable = CreateLiteral("@stmt", LiteralType.Variable);
                return executeSp;
            }
    
        ''' <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> 
        ''' <param name="statementScript"></param> 
        ''' <returns></returns> 
        Private Shared Function CreateExecuteSql(ByVal statementScript As String) As ExecuteStatement
            ' define a new Exec statement 
            Dim executeSp As New ExecuteStatement()
            Dim spExecute As New ExecutableProcedureReference()
            executeSp.ExecutableEntity = spExecute
    
            ' define the name of the procedure that you want to execute, in this case sp_executesql 
            Dim procName As New SchemaObjectName()
            procName.Identifiers.Add(CreateIdentifier("sp_executesql", QuoteType.NotQuoted))
            Dim procRef As New ProcedureReference()
            procRef.Name = procName
            spExecute.ProcedureReference = procRef
    
            ' add the script parameter, constructed from the provided statement script 
            Dim scriptParam As New ExecuteParameter()
            spExecute.Parameters.Add(scriptParam)
            scriptParam.ParameterValue = CreateLiteral(statementScript, LiteralType.UnicodeStringLiteral)
            scriptParam.Variable = CreateLiteral("@stmt", LiteralType.Variable)
            Return executeSp
        End Function
    

    Tipi, metodi e proprietà principali includono i seguenti: ExecuteStatement, ExecutableProcedureReference, SchemaObjectName, ProcedureReference e ExecuteParameter.

Per aggiungere il metodo CreateLiteral

  • Aggiungere il codice seguente per definire il metodo CreateLiteral. Questo metodo crea un oggetto Literal del tipo specificato dalla stringa fornita:

            /// <summary>
            /// The CreateLiteral method creates a Literal object of the specified type from the provided string
            /// </summary>
            /// <param name="value"></param>
            /// <param name="type"></param>
            /// <returns></returns>
            private static Literal CreateLiteral(string value, LiteralType type)
            {
                Literal l = new Literal();
                l.Value = value;
                l.LiteralType = type;
                return l;
            }
    
        ''' <summary> 
        ''' The CreateLiteral method creates a Literal object of the specified type from the provided string 
        ''' </summary> 
        ''' <param name="value"></param> 
        ''' <param name="type"></param> 
        ''' <returns></returns> 
        Private Shared Function CreateLiteral(ByVal value As String, ByVal type As LiteralType) As Literal
            Dim l As New Literal()
            l.Value = value
            l.LiteralType = type
            Return l
        End Function
    

    Tipi, metodi e proprietà principali includono i seguenti: Literal e LiteralType.

Per aggiungere il metodo CreateIdentifier

  • Aggiungere il codice seguente per definire il metodo CreateIdentifier. Questo metodo crea un oggetto Identifier che utilizza il tipo citazione specificata dalla stringa fornita:

            /// <summary>
            /// The CreateIdentifier method returns a Identifier with the specified value and quoting type
            /// </summary>
            /// <param name="value"></param>
            /// <param name="quoteType"></param>
            /// <returns></returns>
            private static Identifier CreateIdentifier(string value, QuoteType quoteType)
            {
                Identifier id = new Identifier();
                id.Value = value;
                id.QuoteType = quoteType;
                return id;
            }
    
        ''' <summary> 
        ''' The CreateIdentifier method returns a Identifier with the specified value and quoting type 
        ''' </summary> 
        ''' <param name="value"></param> 
        ''' <param name="quoteType"></param> 
        ''' <returns></returns> 
        Private Shared Function CreateIdentifier(ByVal value As String, ByVal quoteType As QuoteType) As Identifier
            Dim id As New Identifier()
            id.Value = value
            id.QuoteType = quoteType
            Return id
        End Function
    

    Tipi, metodi e proprietà principali includono i seguenti: Identifier e QuoteType.

Per aggiungere il metodo CreateCompletedBatchesName

  • Aggiungere il codice seguente per definire il metodo CreateCompletedBatchesName. Questo metodo crea il nome che sarà inserito nella tabella temporanea per un batch:

            /// <summary>
            /// The CreateCompletedBatchesName method creates the name that will be inserted
            /// into the temporary table for a batch.
            /// </summary>
            /// <returns></returns>
            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> 
        ''' The CreateCompletedBatchesName method creates the name that will be inserted 
        ''' into the temporary table for a batch. 
        ''' </summary> 
        ''' <returns></returns> 
        Private Shared Function CreateCompletedBatchesName() As SchemaObjectName
            Dim name As 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
        End Function
    

    Tipi, metodi e proprietà principali includono i seguenti:SchemaObjectName.

Per aggiungere il metodo IsStatementEscaped

  • Aggiungere il codice seguente per definire il metodo IsStatementEscaped. Questo metodo determina se il tipo di elemento del modello richiede che per l'istruzione venga eseguito il wrapping in un'istruzione EXEC sp_executesql prima che possa essere inclusa in un'istruzione IF:

            /// <summary>
            /// Helper method that determins whether the specified statement needs to
            /// be escaped
            /// </summary>
            /// <param name="smnt"></param>
            /// <returns></returns>
            private static bool IsStatementEscaped(IModelElement element)
            {
                return element is ISql90Schema
                    || element is ISqlProcedure
                    || element is ISqlView
                    || element is ISqlFunction
                    || element is ISqlTrigger;
            }
    
        ''' <summary> 
        ''' Helper method that determins whether the specified statement needs to 
        ''' be escaped 
        ''' </summary> 
        ''' <param name="element"></param> 
        ''' <returns></returns> 
        Private Shared Function IsStatementEscaped(ByVal element As IModelElement) As Boolean
            Return TypeOf element Is ISql90Schema OrElse TypeOf element Is ISqlProcedure OrElse TypeOf element Is ISqlView OrElse TypeOf element Is ISqlFunction OrElse TypeOf element Is ISqlTrigger
        End Function
    

    Tipi, metodi e proprietà principali includono i seguenti: IModelElement, ISql90Schema, ISqlProcedure, ISqlView, ISqlFunction e ISqlTrigger.

Per aggiungere il metodo CreateBatchCompleteInsert

  • Aggiungere il codice seguente per definire il metodo CreateBatchCompleteInsert. Questo metodo crea l'istruzione INSERT che sarà aggiunta allo script di distribuzione per tenere traccia di stato di avanzamento di esecuzione degli script:

            /// <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();
                SchemaObjectDataModificationTarget batchesCompleted = new SchemaObjectDataModificationTarget();
                insert.Target = batchesCompleted;
                batchesCompleted.SchemaObject = CreateCompletedBatchesName();
    
                // Build the columns inserted into
                Column batchIdColumn = new Column();
                batchIdColumn.Identifiers.Add(CreateIdentifier(BatchIdColumnName, QuoteType.NotQuoted));
    
                Column descriptionColumn = new Column();
                descriptionColumn.Identifiers.Add(CreateIdentifier(DescriptionColumnName, QuoteType.NotQuoted));
    
                insert.Columns.Add(batchIdColumn);
                insert.Columns.Add(descriptionColumn);
    
                // Build the values inserted
                ValuesInsertSource valueSource = new ValuesInsertSource();
                insert.InsertSource = valueSource;
    
                RowValue values = new RowValue();
                values.ColumnValues.Add(CreateLiteral(batchId.ToString(), LiteralType.Integer));
                values.ColumnValues.Add(CreateLiteral(batchDescription, LiteralType.UnicodeStringLiteral));
                valueSource.RowValues.Add(values);
    
                return insert;
            }
    
        ''' <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 Shared Function CreateBatchCompleteInsert(ByVal batchId As Integer, ByVal batchDescription As String) As InsertStatement
            Dim insert As New InsertStatement()
            Dim batchesCompleted As New SchemaObjectDataModificationTarget()
            insert.Target = batchesCompleted
            batchesCompleted.SchemaObject = CreateCompletedBatchesName()
    
            ' Build the columns inserted into 
            Dim batchIdColumn As New Column()
            batchIdColumn.Identifiers.Add(CreateIdentifier(BatchIdColumnName, QuoteType.NotQuoted))
    
            Dim descriptionColumn As New Column()
            descriptionColumn.Identifiers.Add(CreateIdentifier(DescriptionColumnName, QuoteType.NotQuoted))
    
            insert.Columns.Add(batchIdColumn)
            insert.Columns.Add(descriptionColumn)
    
            ' Build the values inserted 
            Dim valueSource As New ValuesInsertSource()
            insert.InsertSource = valueSource
    
            Dim values As New RowValue()
            values.ColumnValues.Add(CreateLiteral(batchId.ToString(), LiteralType.[Integer]))
            values.ColumnValues.Add(CreateLiteral(batchDescription, LiteralType.UnicodeStringLiteral))
            valueSource.RowValues.Add(values)
    
            Return insert
        End Function
    

    Tipi, metodi e proprietà principali includono i seguenti: InsertStatement, SchemaObjectDataModificationTarget, Column, ValuesInsertSource e RowValue.

Per aggiungere il metodo CreateIfNotExecutedStatement

  • Aggiungere il codice seguente per definire il metodo CreateIfNotExecutedStatement. Questo metodo genera un'istruzione IF che controlla se nella tabella temporanea dei batch eseguiti è indicato che questo batch è già stato eseguito:

            /// <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 will look 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();
                Subquery subQuery = new Subquery();
                existsExp.Subquery = subQuery;
    
                QuerySpecification select = new QuerySpecification();
                subQuery.QueryExpression = select;
                select.SelectElements.Add(CreateLiteral("1", LiteralType.Integer));
                SchemaObjectTableSource completedBatchesTable = new SchemaObjectTableSource();
                select.FromClauses.Add(completedBatchesTable);
                completedBatchesTable.SchemaObject = CreateCompletedBatchesName();
    
                WhereClause where = new WhereClause();
                select.WhereClause = where;
    
                Column batchIdColumn = new Column();
                batchIdColumn.Identifiers.Add(CreateIdentifier(BatchIdColumnName, QuoteType.SquareBracket));
                Literal batchIdValue = CreateLiteral(batchId.ToString(), LiteralType.Integer);
    
                BinaryExpression stepsEqual = new BinaryExpression();
                where.SearchCondition = stepsEqual;
                stepsEqual.BinaryExpressionType = BinaryExpressionType.Equals;
                stepsEqual.FirstExpression = batchIdColumn;
                stepsEqual.SecondExpression = batchIdValue;
    
                // Put together the rest of the statement
                IfStatement ifNotExists = new IfStatement();
                UnaryExpression notExp = new UnaryExpression();
                ifNotExists.Predicate = notExp;
                notExp.UnaryExpressionType = UnaryExpressionType.Not;
                notExp.Expression = existsExp;
    
                return ifNotExists;
            }
    
        ''' <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 will look like this 
        ''' 
        ''' if not exists(select 1 from [tempdb].[dbo].[$(CompletedBatches)] 
        ''' where BatchId = batchId) 
        ''' begin 
        ''' end 
        ''' </summary> 
        ''' <param name="batchId"></param> 
        ''' <returns></returns> 
        Private Shared Function CreateIfNotExecutedStatement(ByVal batchId As Integer) As IfStatement
            ' Create the exists/select statement 
            Dim existsExp As New ExistsPredicate()
            Dim subQuery As New Subquery()
            existsExp.Subquery = subQuery
    
            Dim [select] As New QuerySpecification()
            subQuery.QueryExpression = [select]
            [select].SelectElements.Add(CreateLiteral("1", LiteralType.[Integer]))
            Dim completedBatchesTable As New SchemaObjectTableSource()
            [select].FromClauses.Add(completedBatchesTable)
            completedBatchesTable.SchemaObject = CreateCompletedBatchesName()
    
            Dim where As New WhereClause()
            [select].WhereClause = where
    
            Dim batchIdColumn As New Column()
            batchIdColumn.Identifiers.Add(CreateIdentifier(BatchIdColumnName, QuoteType.SquareBracket))
            Dim batchIdValue As Literal = CreateLiteral(batchId.ToString(), LiteralType.[Integer])
    
            Dim stepsEqual As New BinaryExpression()
            where.SearchCondition = stepsEqual
            stepsEqual.BinaryExpressionType = BinaryExpressionType.Equals
            stepsEqual.FirstExpression = batchIdColumn
            stepsEqual.SecondExpression = batchIdValue
    
            ' Put together the rest of the statement 
            Dim ifNotExists As New IfStatement()
            Dim notExp As New UnaryExpression()
            ifNotExists.Predicate = notExp
            notExp.UnaryExpressionType = UnaryExpressionType.[Not]
            notExp.Expression = existsExp
    
            Return ifNotExists
        End Function
    

    Tipi, metodi e proprietà principali includono i seguenti: IfStatement, ExistsPredicate, Subquery, SchemaObjectTableSource, WhereClause, Column, Literal, BinaryExpression e UnaryExpression

Per aggiungere il metodo GetStepInfo

  1. Aggiungere il codice seguente per definire il metodo GetStepInfo. Il metodo:

            /// <summary>
            /// Helper method that generates a useful description of the step.
            /// </summary>
            /// <param name="context"></param>
            /// <param name="domStep"></param>
            /// <param name="stepDescription"></param>
            /// <param name="element"></param>
            private static void GetStepInfo(
                DeploymentPlanContributorContext context, 
                DeploymentScriptDomStep domStep,
                out string stepDescription,
                out IModelElement element)
            {
                element = null;
                CreateElementStep createStep = null;
                AlterElementStep alterStep = null;
                DropElementStep dropStep = null;
    
                // figure out what type of step we've got, and retrieve
                // either the source or target element.
                if ((createStep = domStep as CreateElementStep) != null)
                {
                    element = createStep.SourceElement;
                }
                else if ((alterStep = domStep as AlterElementStep) != null)
                {
                    element = alterStep.SourceElement;
                }
                else if ((dropStep = domStep as DropElementStep) != null)
                {
                    element = dropStep.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 = context.Source.DatabaseSchemaProvider.UserInteractionServices.GetElementName(
                        element, Microsoft.Data.Schema.ElementNameStyle.FullyQualifiedName);
    
                    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;
                }
            }
    
        ''' <summary> 
        ''' Helper method that generates a useful description of the step. 
        ''' </summary> 
        ''' <param name="context"></param> 
        ''' <param name="domStep"></param> 
        ''' <param name="stepDescription"></param> 
        ''' <param name="element"></param> 
        Private Shared Sub GetStepInfo(ByVal context As DeploymentPlanContributorContext, ByVal domStep As DeploymentScriptDomStep, ByRef stepDescription As String, ByRef element As IModelElement)
            element = Nothing
            Dim createStep As CreateElementStep = Nothing
            Dim alterStep As AlterElementStep = Nothing
            Dim dropStep As DropElementStep = Nothing
    
            ' figure out what type of step we've got, and retrieve 
            ' either the source or target element. 
            If (InlineAssignHelper(createStep, TryCast(domStep, CreateElementStep))) IsNot Nothing Then
                element = createStep.SourceElement
            ElseIf (InlineAssignHelper(alterStep, TryCast(domStep, AlterElementStep))) IsNot Nothing Then
                element = alterStep.SourceElement
            ElseIf (InlineAssignHelper(dropStep, TryCast(domStep, DropElementStep))) IsNot Nothing Then
                element = dropStep.TargetElement
            End If
    
            ' construct the step description by concatenating the type and the fully qualified 
            ' name of the associated element. 
            Dim stepTypeName As String = domStep.[GetType]().Name
            If element IsNot Nothing Then
                Dim elementName As String = context.Source.DatabaseSchemaProvider.UserInteractionServices.GetElementName(element, Microsoft.Data.Schema.ElementNameStyle.FullyQualifiedName)
    
                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
            End If
        End Sub
        Private Shared Function InlineAssignHelper(Of T)(ByRef target As T, ByVal value As T) As T
            target = value
            Return value
        End Function
    

    Tipi, metodi e proprietà principali includono i seguenti: DeploymentPlanContributorContext, DeploymentScriptDomStep, IModelElement, CreateElementStep, AlterElementStep e DropElementStep.

  2. Salvare le modifiche a Class1.cs.

    Compilare quindi la libreria di classi.

Per firmare e compilare l'assembly

  1. Scegliere Proprietà di MyOtherDeploymentContributor dal menu Progetto.

  2. Fare clic sulla scheda Firma.

  3. Fare clic su Firma assembly.

  4. In Scegli un file chiave con nome sicuro fare clic su <Nuovo>.

  5. Nella finestra di dialogo Crea chiave con nome sicuro digitare MyRefKey nel campo Nome file di chiave.

  6. (Facoltativo) È possibile specificare una password per il file di chiave con nome sicuro.

  7. Scegliere OK.

  8. Scegliere Salva tutto dal menu File.

  9. Scegliere Compila soluzione dal menu Compila.

    Sarà quindi necessario installare e registrare l'assembly in modo che venga caricato quando si distribuiscono progetti di database.

Installare un collaboratore alla distribuzione

Per installare un collaboratore alla distribuzione, è necessario effettuare le attività seguenti:

  • Copiare l'assembly e il file con estensione pdb associato nella cartella Extensions

  • Creare un file Extensions.xml per registrare il collaboratore alla distribuzione in modo che venga caricato quando si distribuiscono i progetti di database

Per installare l'assembly MyOtherDeploymentContributor

  1. Creare una cartella denominata MyExtensions nella cartella %Programmi%\Microsoft Visual Studio 10.0\VSTSDB\Extensions.

  2. Copiare l'assembly firmato (MyOtherDeploymentContributor.dll) nella cartella %Programmi%\Microsoft Visual Studio 10.0\VSTSDB\Extensions\MyExtensions.

    Nota

    Si consiglia di non copiare i file XML direttamente nella cartella %Programmi%\Microsoft Visual Studio 10.0\VSTSDB\Extensions. Se si utilizza una sottocartella, si eviterà che vengano apportate modifiche accidentali agli altri file forniti con Visual Studio.

    Sarà quindi necessario registrare l'assembly, che è un tipo di estensione di funzionalità, in modo che venga visualizzato in Visual Studio.

Per registrare l'assembly MyOtherDeploymentContributor

  1. Scegliere Altre finestre dal menu Visualizza, quindi fare clic su Finestra di comando per aprire la finestra Comando.

  2. Nella finestra Comando digitare il codice seguente. Sostituire FilePath con il percorso e il nome del file con estensione dll compilato. Racchiudere il percorso e il nome del file tra virgolette.

    Nota

    Per impostazione predefinita, il percorso del file con estensione dll compilato è PercorsoSoluzione\bin\Debug o PercorsoSoluzione\bin\Release.

    ? System.Reflection.Assembly.LoadFrom(@"FilePath").FullName
    
    ? System.Reflection.Assembly.LoadFrom("FilePath").FullName
    
  3. Premere Invio.

  4. Copiare negli Appunti la riga risultante, che dovrebbe essere simile alla seguente:

    "GeneratorAssembly, Version=1.0.0.0, Culture=neutral, PublicKeyToken=nnnnnnnnnnnnnnnn"
    
  5. Aprire un editor di testo, ad esempio Blocco note.

    Nota importanteImportante

    In Windows Vista e Microsoft Windows Server 2008 aprire l'editor come amministratore in modo che sia possibile salvare il file nella cartella Programmi.

  6. Fornire le seguenti informazioni specificando il nome dell'assembly personale, il token di chiave pubblica e il tipo di estensione:

    <?xml version="1.0" encoding="utf-8" ?> 
    <extensions assembly="" version="1" xmlns="urn:Microsoft.Data.Schema.Extensions" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="urn:Microsoft.Data.Schema.Extensions Microsoft.Data.Schema.Extensions.xsd">
      <extension type="MyOtherDeploymentContributor.SqlRestartableScriptContributor" 
    assembly="MyOtherDeploymentContributor, Version=1.0.0.0, Culture=neutral, PublicKeyToken=<enter key here>" enabled="true" />
    </extensions>
    

    Questo file XML viene utilizzato per registrare la classe che eredita da DeploymentPlanExecutor.

  7. Salvare il file con il nome MyOtherDeploymentContributor.extensions.xml nella cartella %Programmi%\Microsoft Visual Studio 10.0\VSTSDB\Extensions\MyExtensions.

  8. Chiudere Visual Studio.

    Si distribuirà quindi un progetto di database per testare il collaboratore.

Testare il collaboratore alla distribuzione

Per testare il collaboratore alla distribuzione, è necessario effettuare l'attività seguente:

  • Distribuire il progetto di database tramite MSBuild e fornendo il parametro adatto

Poiché questo collaboratore alla distribuzione è sempre abilitato, non è necessario modificare il progetto di database per aggiungere eventuali proprietà.

Distribuire il progetto di database

Per distribuire il progetto di database e generare un rapporto di distribuzione

  1. Aprire un prompt dei comandi di Visual Studio. Fare clic sul pulsante Start, scegliere Tutti i programmi, quindi Microsoft Visual Studio 2010, Visual Studio Tools e fare clic su Prompt dei comandi di Visual Studio 2010.

  2. Al prompt dei comandi individuare la cartella che contiene il progetto di database.

  3. Al prompt dei comandi digitare la riga di comando seguente:

    MSBuild /t:Deploy MyDatabaseProject.dbproj
    

    Sostituire MyDatabaseProject con il nome del progetto di database che si desidera distribuire.

  4. Esaminare lo script di distribuzione risultante. Poco prima della sezione identificata da "Pre-Deployment Script Template", dovrebbe essere visualizzato testo simile al seguente 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)]
    end
    

    Più avanti nello script di distribuzione, intorno a ciascun batch, viene visualizzata un'istruzione IF che racchiude l'istruzione originale. Ad esempio, per un'istruzione CREATE SCHEMA potrebbe essere visualizzato quanto segue:

    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;
        END
    

    Notare che CREATE SCHEMA è una delle istruzioni che devono essere incluse in un'istruzione EXECUTE sp_executesql all'interno dell'istruzione IF. Istruzioni quale CREATE TABLE non richiedono l'istruzione EXECUTE sp_executesq e saranno simili all'esempio seguente:

    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;
        END
    

    Nota

    Se si distribuisce un progetto di database identico al database di destinazione, il rapporto risultante non sarà molto significativo. Per risultati più significativi, distribuire le modifiche a un database o distribuisce un nuovo database.

    È possibile aggiungere, rimuovere o modificare batch o istruzioni in qualsiasi piano di distribuzione tramite DeploymentPlanModifier.

Passaggi successivi

È possibile sperimentare altri tipi di modifiche che è possibile apportare ai piani di distribuzione prima che vengano eseguiti. Alcuni altri tipi di modifiche che si consiglia apportare includono: aggiunta di una proprietà estesa a tutti gli oggetti di database che associano a tali oggetti un numero di versione, aggiunta o rimozione di ulteriori istruzioni di stampa diagnostiche o commenti dagli script di distribuzione e così via.

Vedere anche

Concetti

Estensione delle funzionalità di database di Visual Studio

Altre risorse

Personalizzare compilazione e distribuzione del database tramite collaboratori alla compilazione e distribuzione

Procedura dettagliata: estendere la compilazione del progetto di database per generare statistiche dal modello

Procedura dettagliata: estendere la distribuzione del progetto di database per analizzare il piano di distribuzione