逐步解說:擴充資料庫專案部署以分析部署計劃

您可以建立部署參與者,以在部署資料庫專案時執行自訂動作。 您可以建立 DeploymentPlanModifier 或 DeploymentPlanExecutor。 DeploymentPlanModifier 可用於在執行計劃之前變更計劃,DeploymentPlanExecutor 則可用於在正在執行計劃時執行作業。 在這個逐步解說中,您會建立名為 DeploymentUpdateReportContributor 的 DeploymentPlanExecutor,它會建立報告來列出部署資料庫專案時會執行的動作。 因為這個建置參與者需要一個參數來控制是否產生報告,所以您必須執行一個額外必要步驟。

在這個逐步解說中,您將完成下列主要工作:

  • 建立 DeploymentPlanExecutor 型別的部署參與者

  • 安裝部署參與者

  • 測試部署參與者

必要條件

您需要下列元件才能完成此逐步解說:

  • 電腦上已安裝 Visual Studio 2010 Premium 或 Visual Studio 2010 Ultimate。

  • 包含資料庫物件的資料庫專案

  • 可以對其部署資料庫專案的 SQL Server 執行個體

注意事項注意事項

此逐步解說適合已經熟悉 Visual Studio 資料庫功能的使用者使用。 您也必須熟悉基本的 Visual Studio 概念,例如如何建立類別庫,以及如何使用程式碼編輯器,將程式碼加入至類別。

建立部署參與者

若要建立部署參與者,您必須執行下列工作:

  • 建立類別庫專案並加入必要的參考

  • 定義名為 DeploymentUpdateReportContributor 的類別,該類別繼承自 DeploymentPlanExecutor

  • 覆寫 OnPopulateArguments 和 OnExecute 方法

  • 加入私用 Helper 類別

  • 建置產生的組件

若要建立類別庫專案

  1. 建立名為 MyDeploymentContributor 的 Visual Basic 或 Visual C# 類別庫專案。

  2. 在 [方案總管] 中,以滑鼠右鍵按一下 [參考] 資料夾,然後按一下 [加入參考]。

  3. 按一下 [.NET] 索引標籤。

  4. 反白顯示 [Microsoft.Data.Schema] 和 [Microsoft.Data.Schema.Sql] 項目,然後按一下 [確定]。

    接下來,開始將程式碼加入至類別。

若要定義 DeploymentUpdateReportContributor 類別

  1. 在程式碼編輯器中,將 class1.cs 檔更新為符合下列 using 或 Imports 陳述式:

    using System;
    using System.Collections.Generic;
    using System.Text;
    using Microsoft.Data.Schema.Build;
    using Microsoft.Data.Schema.Extensibility;
    using Microsoft.Data.Schema.Sql;
    using System.IO;
    using Microsoft.Data.Schema.SchemaModel;
    using System.Xml;
    using Microsoft.Data.Schema;
    using Microsoft.Data.Schema.Sql.Build;
    
    Imports System
    Imports System.Collections.Generic
    Imports System.Text
    Imports Microsoft.Data.Schema.Build
    Imports Microsoft.Data.Schema.Extensibility
    Imports Microsoft.Data.Schema.Sql
    Imports System.IO
    Imports Microsoft.Data.Schema.SchemaModel
    Imports System.Xml
    Imports Microsoft.Data.Schema
    Imports Microsoft.Data.Schema.Sql.Build
    
  2. 將類別定義更新為符合下列各行程式碼:

        [DatabaseSchemaProviderCompatibility(typeof(SqlDatabaseSchemaProvider))]
        class DeploymentUpdateReportContributor : DeploymentPlanExecutor
        {
        }
    
    ''' <summary>
    ''' The DeploymentUpdateReportContributor class demonstrates
    ''' how you can create a class that inherits DeploymentPlanExecutor
    ''' to perform actions when you execute the deployment plan
    ''' for a database project.
    ''' </summary>
    <DatabaseSchemaProviderCompatibility(GetType(SqlDatabaseSchemaProvider))>
    Public Class DeploymentUpdateReportContributor
        Inherits DeploymentPlanExecutor
    End Class
    

    現在,您已定義建置參與者,而且已使用屬性表示這個參與者與所有繼承自 SqlDatabaseSchemaProvider 的資料庫結構描述提供者都相容。

  3. 接下來加入下列成員,您會使用這些成員讓這個提供者能夠接受命令列參數:

            private const string GenerateUpdateReport = "GenerateUpdateReport";
    
        Dim GenerateUpdateReport As String = "GenerateUpdateReport"
    

    這個成員讓使用者得以指定是否應該使用 GenerateUpdateReport 選項來產生報告。

    接下來,您會覆寫 OnPopulateArguments 方法以建置要傳遞給部署參與者的引數清單。

若要覆寫 OnPopulateArguments

  • 將下列覆寫方法加入至 DeploymentUpdateReportContributor 類別:

        /// <summary>
        /// Override the OnPopulateArgument method to build a list of arguments from the input
        /// configuration information.
        /// </summary>
            protected override IList<ContributorArgumentConfiguration> OnPopulateArguments()
            {
                List<ContributorArgumentConfiguration> args = new List<ContributorArgumentConfiguration>();
    
                // Generate reports when in debug configuration
                args.Add(new ContributorArgumentConfiguration( GenerateUpdateReport, "true", "'$(Configuration)' == 'Debug'"));
                return args;
            }
    
        ''' <summary>
        ''' Override the OnPopulateArgument method to build a list of arguments from the input
        ''' configuration information.
        ''' </summary>
        Protected Overloads Overrides Function OnPopulateArguments() As IList(Of ContributorArgumentConfiguration)
            Dim args As New List(Of ContributorArgumentConfiguration)()
    
            ' Generate reports when in debug configuration 
            args.Add(New ContributorArgumentConfiguration(GenerateUpdateReport, "true", "'$(Configuration)' == 'Debug'"))
            Return args
        End Function
    

    您建置了一個 ContributorArgumentConfiguration 物件,並將其加入至引數清單。 根據預設,當您產生偵錯組建時,就會產生報表。

    接下來,您會覆寫 OnExecute 方法,以便加入要在部署資料庫專案時執行的程式碼。

若要覆寫 OnExecute

  • 將下列方法加入至 DeploymentUpdateReportContributor 類別:

        /// <summary>
        /// Override the OnExecute method to perform actions when you execute the deployment plan for
        /// a database project.
        /// </summary>
            protected override void OnExecute(DeploymentPlanContributorContext context)
            {
                // determine whether the user specified a report is to be generated
                bool generateReport = false;
                string generateReportValue;
                if (context.Arguments.TryGetValue(GenerateUpdateReport, out generateReportValue) == false)
                {
                    // couldn't find the GenerateUpdateReport argument, so do not generate
                    generateReport = false;
                }
                else
                {
                    // GenerateUpdateReport argument was specified, try to parse the value
                    if (bool.TryParse(generateReportValue, out generateReport))
                    {
                        // if we end up here, the value for the argument was not valid.
                        // default is false, so do nothing.
                    }
                }
    
                if (generateReport == false)
                {
                    // if user does not want to generate a report, we are done
                    return;
                }
    
                // We will output to the same directory where the deployment script
                // is output or to the current directory
                string reportPrefix = context.Options.TargetDatabaseName;
                string reportPath;
                if (string.IsNullOrEmpty(context.DeploymentScriptPath))
                {
                    reportPath = Environment.CurrentDirectory;
                }
                else
                {
                    reportPath = Path.GetDirectoryName(context.DeploymentScriptPath);
                }
                FileInfo summaryReportFile = new FileInfo(Path.Combine(reportPath, reportPrefix + ".summary.xml"));
                FileInfo detailsReportFile = new FileInfo(Path.Combine(reportPath, reportPrefix + ".details.xml"));
    
                // Generate the reports by using the helper class DeploymentReportWriter
                DeploymentReportWriter writer = new DeploymentReportWriter(context);
                writer.WriteReport(summaryReportFile);
                writer.IncludeScripts = true;
                writer.WriteReport(detailsReportFile);
    
                string msg = "Deployment reports ->"
                    + Environment.NewLine + summaryReportFile.FullName
                    + Environment.NewLine + detailsReportFile.FullName;
    
                DataSchemaError reportMsg = new DataSchemaError(msg, ErrorSeverity.Message);
                base.PublishMessage(reportMsg);
            }
    
        ''' <summary>
        ''' Override the OnExecute method to perform actions when you execute the deployment plan for
        ''' a database project.
        ''' </summary>
        Protected Overloads Overrides Sub OnExecute(ByVal context As DeploymentPlanContributorContext)
            ' output the names and values for any provided arguments 
            For Each arg As KeyValuePair(Of String, String) In context.Arguments
                Dim argMsg As New DataSchemaError((arg.Key & "=") + arg.Value, ErrorSeverity.Message)
                Me.PublishMessage(argMsg)
            Next
            ' determine whether the user specified a report is to be generated 
            Dim generateReport As Boolean = False
            Dim generateReportValue As String
            If context.Arguments.TryGetValue(GenerateUpdateReport, generateReportValue) = False Then
                ' couldn't find the GenerateUpdateReport argument, so do not generate 
                generateReport = False
            Else
                ' GenerateUpdateReport argument was specified, try to parse the value 
                If Boolean.TryParse(generateReportValue, generateReport) Then
                    ' if we end up here, the value for the argument was not valid. 
                    ' default is false, so do nothing. 
                End If
            End If
    
            If generateReport = False Then
                ' if user does not want to generate a report, we are done 
                Exit Sub
            End If
    
            ' We will output to the same directory where the deployment script 
            ' is output or to the current directory 
            Dim reportPrefix As String = context.Options.TargetDatabaseName
            Dim reportPath As String
            If String.IsNullOrEmpty(context.DeploymentScriptPath) Then
                reportPath = Environment.CurrentDirectory
            Else
                reportPath = Path.GetDirectoryName(context.DeploymentScriptPath)
            End If
            Dim summaryReportFile As New FileInfo(Path.Combine(reportPath, reportPrefix & ".summary.xml"))
            Dim detailsReportFile As New FileInfo(Path.Combine(reportPath, reportPrefix & ".details.xml"))
    
            ' Generate the reports by using the helper class DeploymentReportWriter 
            Dim writer As New DeploymentReportWriter(context)
            writer.WriteReport(summaryReportFile)
            writer.IncludeScripts = True
            writer.WriteReport(detailsReportFile)
    
            Dim msg As String = ("Deployment reports ->" & Environment.NewLine) + summaryReportFile.FullName + Environment.NewLine + detailsReportFile.FullName
    
            Dim reportMsg As New DataSchemaError(msg, ErrorSeverity.Message)
            MyBase.PublishMessage(reportMsg)
        End Sub
    

    OnExecute 方法接受 DeploymentPlanContributorContext 物件,這個物件可用來存取任何指定的引數、來源和目標資料庫模型、建置屬性和擴充檔。 在這個範例中,我們會擷取模型,然後呼叫 Helper 函式來輸出模型的相關資訊。 這個方法也接受 ErrorManager 以用來報告任何發生的錯誤。

    其他要注意的型別和方法包括:DataSchemaModelModelStoreModelComparisonResultDatabaseSchemaProviderDeploymentPlanHandleSchemaDeploymentOptions

    接下來,您會定義用以檢查部署計劃詳細資料的 Helper 類別。

若要加入會產生報告主體的 Helper 類別

  • 首先,加入下列程式碼以加入 Helper 類別和其方法的基本架構:

            /// <summary>
            /// This class is used to generate a deployment
            /// report. 
            /// </summary>
            private class DeploymentReportWriter
            {
                /// <summary>
                /// The constructor accepts the same context info
                /// that was passed to the OnExecute method of the
                /// deployment contributor.
                /// </summary>
                public DeploymentReportWriter(DeploymentPlanContributorContext context)
                {
               }
                /// <summary>
                /// Property indicating whether script bodies
                /// should be included in the report.
                /// </summary>
                public bool IncludeScripts { get; set; }
    
                /// <summary>
                /// Drives the report generation, opening files, 
                /// writing the beginning and ending report elements,
                /// and calling helper methods to report on the
                /// plan operations.
                /// </summary>
                internal void WriteReport(FileInfo reportFile)
                {
                }
    
                /// <summary>
                /// Writes details for the various operation types
                /// that could be contained in the deployment plan.
                /// Optionally writes script bodies, depending on
                /// the value of the IncludeScripts property.
                /// </summary>
                private void ReportPlanOperations(XmlWriter xmlw)
                {
                }
    
                /// <summary>
                /// Returns the category of the specified element
                /// in the source model
                /// </summary>
                private string GetElementCategory(IModelElement element)
                {
                }
    
                /// <summary>
                /// Returns the name of the specified element
                /// in the source model
                /// </summary>
                private string GetElementName(IModelElement element)
                {
                }
            }
    
    ''' <summary>
    ''' This class is used to generate a deployment
    ''' report. 
    ''' </summary>
    Private Class DeploymentReportWriter
    
        Public Sub New(ByVal context As DeploymentPlanContributorContext)
        End Sub
    
        Private _includeScripts As Boolean
        ''' <summary>
        ''' Property indicating whether script bodies
        ''' should be included in the report.
        ''' </summary>
        Public Property IncludeScripts() As Boolean
            Get
                IncludeScripts = _includeScripts
            End Get
            Set(ByVal value As Boolean)
                _includeScripts = value
            End Set
        End Property
    
    
        ''' <summary> 
        ''' Drives the report generation, opening files, 
        ''' writing the beginning and ending report elements, 
        ''' and calling helper methods to report on the 
        ''' plan operations. 
        ''' </summary> 
        Friend Sub WriteReport(ByVal reportFile As FileInfo)
        End Sub
    
        ''' <summary> 
        ''' Writes details for the various operation types 
        ''' that could be contained in the deployment plan. 
        ''' Optionally writes script bodies, depending on 
        ''' the value of the IncludeScripts property. 
        ''' </summary> 
        Private Sub ReportPlanOperations(ByVal xmlw As XmlWriter)
        End Sub
        ''' <summary>
        ''' Returns the category of the specified element
        ''' in the source model
        ''' </summary> 
        Private Function GetElementCategory(ByVal element As IModelElement) As String
            Return ""
        End Function
    
        ''' <summary>
        ''' Returns the name of the specified element
        ''' in the source model
        ''' </summary>
        Private Function GetElementName(ByVal element As IModelElement) As String
            Return ""
        End Function
    End Class
    
  • 將這些變更儲存至 Class1.cs。

    接下來,您會加入類別成員和方法主體。

若要加入類別成員

  • 在程式碼編輯器中,將下列程式碼加入至 DeploymentReportWriter 類別:

                readonly DataSchemaModel _sourceModel;
                readonly ModelComparisonResult _diff;
                readonly DeploymentStep _planHead;
    
            ReadOnly _sourceModel As DataSchemaModel
            ReadOnly _diff As ModelComparisonResult
            ReadOnly _planHead As DeploymentStep
    

    要注意的型別包括:DataSchemaModelModelComparisonResultDeploymentStep

    接下來,您會加入類別建構函式的主體。

若要將方法主體加入至建構函式

  • 加入下列程式碼做為建構函式的主體:

                    if (context == null)
                    {
                        throw new ArgumentNullException("context");
                    }
    
                    // save the source model, source/target differences,
                    // and the beginning of the deployment plan.
                    _sourceModel = context.Source;
                    _diff = context.ComparisonResult;
                    _planHead = context.PlanHandle.Head;
    
                If context Is Nothing Then
                    Throw New ArgumentNullException("context")
                End If
    
                ' save the source model, source/target differences, 
                ' and the beginning of the deployment plan. 
                _sourceModel = context.Source
                _diff = context.ComparisonResult
                _planHead = context.PlanHandle.Head
    

    接下來,您會加入 WriteReport 方法的主體。

若要將方法主體加入至 WriteReport 方法

  • 加入下列程式碼做為 WriteReport 方法的主體:

                    // Assumes that we have a valid report file
                    if (reportFile == null)
                    {
                        throw new ArgumentNullException("reportFile");
                    }
    
                    // set up the XML writer
                    XmlWriterSettings xmlws = new XmlWriterSettings();
                    // Indentation makes it a bit more readable
                    xmlws.Indent = true;
                    FileStream fs = new FileStream(reportFile.FullName, FileMode.Create, FileAccess.Write, FileShare.ReadWrite);
                    XmlWriter xmlw = XmlWriter.Create(fs, xmlws);
    
                    try
                    {
                        xmlw.WriteStartDocument(true);
                        xmlw.WriteStartElement("DeploymentReport");
    
                        // Summary report of the operations that
                        // are contained in the plan.
                        ReportPlanOperations(xmlw);
    
                        // You could add a method call here
                        // to produce a detailed listing of the 
                        // differences between the source and
                        // target model.
                        xmlw.WriteEndElement();
                        xmlw.WriteEndDocument();
                        xmlw.Flush();
                        fs.Flush();
                    }
                    finally
                    {
                        xmlw.Close();
                        fs.Dispose();
                    }
    
                ' Assumes that we have a valid report file 
                If reportFile Is Nothing Then
                    Throw New ArgumentNullException("reportFile")
                End If
    
                ' set up the XML writer 
                Dim xmlws As New XmlWriterSettings()
                ' Indentation makes it a bit more readable 
                xmlws.Indent = True
                Dim fs As New FileStream(reportFile.FullName, FileMode.Create, FileAccess.Write, FileShare.ReadWrite)
                Dim xmlw As XmlWriter = XmlWriter.Create(fs, xmlws)
    
                Try
                    xmlw.WriteStartDocument(True)
                    xmlw.WriteStartElement("DeploymentReport")
    
                    ' Summary report of the operations that 
                    ' are contained in the plan. 
                    ReportPlanOperations(xmlw)
    
                    ' You could add a method call here 
                    ' to produce a detailed listing of the 
                    ' differences between the source and 
                    ' target model. 
                    xmlw.WriteEndElement()
                    xmlw.WriteEndDocument()
                    xmlw.Flush()
                    fs.Flush()
                Finally
                    xmlw.Close()
                    fs.Dispose()
                End Try
    

    要注意的型別為 XmlWriterXmlWriterSettings

    接下來,您會加入 ReportPlanOperations 方法的主體。

若要將方法主體加入至 ReportPlanOperations 方法

  • 加入下列程式碼做為 ReportPlanOperations 方法的主體:

                    // write the node to indicate the start
                    // of the list of operations.
                    xmlw.WriteStartElement("Operations");
    
                    // Loop through the steps in the plan,
                    // starting at the beginning.
                    DeploymentStep currentStep = _planHead;
                    while (currentStep != null)
                    {
                        // Report the type of step
                        xmlw.WriteStartElement(currentStep.GetType().Name);
    
                        // based on the type of step, report
                        // the relevant information.
                        // Note that this procedure only handles 
                        // a subset of all step types.
                        if (currentStep is SqlRenameStep)
                        {
                            SqlRenameStep renameStep = (SqlRenameStep)currentStep;
                            xmlw.WriteAttributeString("OriginalName", renameStep.OldName);
                            xmlw.WriteAttributeString("NewName", renameStep.NewName);
                            xmlw.WriteAttributeString("Category", GetElementCategory(renameStep.RenamedElement));
                        }
                        else if (currentStep is SqlMoveSchemaStep)
                        {
                            SqlMoveSchemaStep moveStep = (SqlMoveSchemaStep)currentStep;
                            xmlw.WriteAttributeString("OrignalName", moveStep.PreviousName);
                            xmlw.WriteAttributeString("NewSchema", moveStep.NewSchema);
                            xmlw.WriteAttributeString("Category", GetElementCategory(moveStep.MovedElement));
                        }
                        else if (currentStep is SqlTableMigrationStep)
                        {
                            SqlTableMigrationStep dmStep = (SqlTableMigrationStep)currentStep;
                            xmlw.WriteAttributeString("Name", GetElementName(dmStep.SourceTable));
                            xmlw.WriteAttributeString("Category", GetElementCategory(dmStep.SourceElement));
                        }
                        else if (currentStep is CreateElementStep)
                        {
                            CreateElementStep createStep = (CreateElementStep)currentStep;
                            xmlw.WriteAttributeString("Name", GetElementName(createStep.SourceElement));
                            xmlw.WriteAttributeString("Category", GetElementCategory(createStep.SourceElement));
                        }
                        else if (currentStep is AlterElementStep)
                        {
                            AlterElementStep alterStep = (AlterElementStep)currentStep;
                            xmlw.WriteAttributeString("Name", GetElementName(alterStep.SourceElement));
                            xmlw.WriteAttributeString("Category", GetElementCategory(alterStep.SourceElement));
                        }
                        else if (currentStep is DropElementStep)
                        {
                            DropElementStep dropStep = (DropElementStep)currentStep;
                            xmlw.WriteAttributeString("Name", GetElementName(dropStep.TargetElement));
                            xmlw.WriteAttributeString("Category", GetElementCategory(dropStep.TargetElement));
                        }
    
                        // If the script bodies are to be included,
                        // add them to the report.
                        if (this.IncludeScripts)
                        {
                            string tsqlBody = currentStep.Action();
                            if (string.IsNullOrEmpty(tsqlBody) == false)
                            {
                                xmlw.WriteCData(tsqlBody);
                            }
                        }
    
                        // close off the current step
                        xmlw.WriteEndElement();
                        currentStep = currentStep.Next;
                    }
                    xmlw.WriteEndElement();
    
                ' write the node to indicate the start 
                ' of the list of operations. 
                xmlw.WriteStartElement("Operations")
    
                ' Loop through the steps in the plan, 
                ' starting at the beginning. 
                Dim currentStep As DeploymentStep = _planHead
                While currentStep IsNot Nothing
                    ' Report the type of step 
                    xmlw.WriteStartElement(currentStep.[GetType]().Name)
    
                    ' based on the type of step, report 
                    ' the relevant information. 
                    If TypeOf currentStep Is SqlRenameStep Then
                        Dim renameStep As SqlRenameStep = DirectCast(currentStep, SqlRenameStep)
                        xmlw.WriteAttributeString("OriginalName", renameStep.OldName)
                        xmlw.WriteAttributeString("NewName", renameStep.NewName)
                        xmlw.WriteAttributeString("Category", GetElementCategory(renameStep.RenamedElement))
                    ElseIf TypeOf currentStep Is SqlMoveSchemaStep Then
                        Dim moveStep As SqlMoveSchemaStep = DirectCast(currentStep, SqlMoveSchemaStep)
                        xmlw.WriteAttributeString("OrignalName", moveStep.PreviousName)
                        xmlw.WriteAttributeString("NewSchema", moveStep.NewSchema)
                        xmlw.WriteAttributeString("Category", GetElementCategory(moveStep.MovedElement))
                    ElseIf TypeOf currentStep Is SqlTableMigrationStep Then
                        Dim dmStep As SqlTableMigrationStep = DirectCast(currentStep, SqlTableMigrationStep)
                        xmlw.WriteAttributeString("Name", GetElementName(dmStep.SourceTable))
                        xmlw.WriteAttributeString("Category", GetElementCategory(dmStep.SourceElement))
                    ElseIf TypeOf currentStep Is CreateElementStep Then
                        Dim createStep As CreateElementStep = DirectCast(currentStep, CreateElementStep)
                        xmlw.WriteAttributeString("Name", GetElementName(createStep.SourceElement))
                        xmlw.WriteAttributeString("Category", GetElementCategory(createStep.SourceElement))
                    ElseIf TypeOf currentStep Is AlterElementStep Then
                        Dim alterStep As AlterElementStep = DirectCast(currentStep, AlterElementStep)
                        xmlw.WriteAttributeString("Name", GetElementName(alterStep.SourceElement))
                        xmlw.WriteAttributeString("Category", GetElementCategory(alterStep.SourceElement))
                    ElseIf TypeOf currentStep Is DropElementStep Then
                        Dim dropStep As DropElementStep = DirectCast(currentStep, DropElementStep)
                        xmlw.WriteAttributeString("Name", GetElementName(dropStep.TargetElement))
                        xmlw.WriteAttributeString("Category", GetElementCategory(dropStep.TargetElement))
                    End If
    
                    ' If the script bodies are to be included, 
                    ' add them to the report. 
                    If Me.IncludeScripts Then
                        Dim tsqlBody As String = currentStep.Action()
                        If String.IsNullOrEmpty(tsqlBody) = False Then
                            xmlw.WriteCData(tsqlBody)
                        End If
                    End If
    
                    ' close off the current step 
                    xmlw.WriteEndElement()
                    currentStep = currentStep.[Next]
                End While
                xmlw.WriteEndElement()
    

    要注意的型別包括:DeploymentStepSqlRenameStepSqlMoveSchemaStepSqlTableMigrationStepCreateElementStepAlterElementStepDropElementStep。 下列步驟類型是這個範例未顯示的其他步驟類型:BeginPostDeploymentScriptStepBeginPreDeploymentScriptStepDeploymentScriptDomStepDeploymentScriptStepEndPostDeploymentScriptStepEndPreDeploymentScriptStep。 您可以尋找 SQL Server 特有步驟:SqlBeginAltersStepSqlBeginDropsStepSqlBeginPreservationStepSqlBeginTransactionStepSqlEndAltersStepSqlEndDropsStepSqlEndPreservationStepSqlEndTransactionStepSqlFinalizeDatabaseAccessStepSqlMoveSchemaStepSqlPrintStepSqlRenameStepSqlTableMigrationStep

    接下來,您會加入 GetElementCategory 方法的主體。

若要將方法主體加入至 GetElementCategory 方法

  • 加入下列程式碼做為 GetElementCategory 方法的主體:

                    return _sourceModel.DatabaseSchemaProvider.UserInteractionServices.GetElementTypeDescription(
                        element.ElementClass);
    
                Return _sourceModel.DatabaseSchemaProvider.UserInteractionServices.GetElementTypeDescription(element.ElementClass)
    

    要注意的型別和方法包括:DataSchemaModelDatabaseSchemaProviderUserInteractionServicesGetElementTypeDescription

    接下來,您會加入 GetElementName 方法的主體。

若要將方法主體加入至 GetElementName 方法

  • 加入下列程式碼做為 GetElementName 方法的主體:

                    return _sourceModel.DatabaseSchemaProvider.UserInteractionServices.GetElementName(
                        element, 
                        ElementNameStyle.FullyQualifiedName);
    
                Return _sourceModel.DatabaseSchemaProvider.UserInteractionServices.GetElementName(element, ElementNameStyle.FullyQualifiedName)
    

    要注意的型別和方法包括:DataSchemaModelDatabaseSchemaProviderUserInteractionServicesGetElementNameElementNameStyle

    將這些變更儲存至類別。 接下來,您會建置類別庫。

若要簽署和建置組件

  1. 按一下 [專案] 功能表上的 [MyDeploymentContributor 屬性]。

  2. 按一下 [簽署] 索引標籤。

  3. 按一下 [簽署組件]。

  4. 在 [選擇強式名稱金鑰檔] 中,按一下 [<新增>]。

  5. 在 [建立強式名稱金鑰] 對話方塊的 [金鑰檔名稱] 中,輸入 MyRefKey。

  6. (選擇性) 您可以為強式名稱金鑰檔指定密碼。

  7. 按一下 [確定]。

  8. 在 [檔案] 功能表上按一下 [全部儲存]。

  9. 在 [建置] 功能表上,按一下 [建置方案]。

    接下來,您必須安裝並註冊組件,以便在部署資料庫專案時可以載入它。

安裝部署參與者

若要安裝部署參與者,您必須執行下列工作:

  • 將組件和相關聯的 .pdb 檔案複製到 Extensions 資料夾

  • 建立 Extensions.xml 檔來註冊部署參與者,以在您部署資料庫專案時載入該部署參與者

若要安裝 MyDeploymentContributor 組件

  1. 在 %Program Files%\Microsoft Visual Studio 10.0\VSTSDB\Extensions 資料夾中建立名為 MyExtensions 的資料夾。

  2. 將已簽署的組件 (MyDeploymentContributor.dll) 與相關聯的 .pdb 檔 (MyDeploymentContributor.pdb) 複製到 %Program Files%\Microsoft Visual Studio 10.0\VSTSDB\Extensions\MyExtensions 資料夾。

    注意事項注意事項

    建議您不要直接將 XML 檔案複製到 %Program Files%\Microsoft Visual Studio 10.0\VSTSDB\Extensions 資料夾中。 如果改用子資料夾,可以防止不小心變更 Visual Studio Premium 隨附的其他檔案。

    接下來,您必須註冊組件 (一種「擴充功能」(Feature Extension) 類型),以便讓它出現在 Visual Studio Premium 中。

若要註冊 MyDeploymentContributor 組件

  1. 按一下 [檢視] 功能表上的 [其他視窗],然後按一下 [命令視窗] 開啟 [命令視窗]。

  2. 在 [命令] 視窗中輸入下列程式碼。 將 FilePath 替代為已編譯之 .dll 檔案的路徑和檔案名稱。 請在路徑和檔案名稱周圍加上引號。

    注意事項注意事項

    根據預設,已編譯之 .dll 檔案的路徑為 <您的方案路徑>\bin\Debug 或 <您的方案路徑>\bin\Release。

    ? System.Reflection.Assembly.LoadFrom(@"FilePath").FullName
    
    ? System.Reflection.Assembly.LoadFrom("FilePath").FullName
    
  3. 按 ENTER。

  4. 將產生的程式碼行複製到剪貼簿中。 此程式碼行應該與下列程式碼相似:

    "MyDeploymentContributor, Version=1.0.0.0, Culture=neutral, PublicKeyToken=nnnnnnnnnnnnnnnn"
    
  5. 開啟純文字編輯器,如 [記事本]。

    重要事項重要事項

    在 Windows Vista 和 Microsoft Windows Server 2008 上,以系統管理員身分開啟編輯器,以便將檔案儲存至 Program Files 資料夾。

  6. 提供下列資訊,並指定您自己的組件名稱、公開金鑰語彙基元和副檔名類型:

    <?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="MyDeploymentContributor.DeploymentUpdateReportContributor" 
    assembly="MyDeploymentContributor, Version=1.0.0.0, Culture=neutral, PublicKeyToken=<enter key here>" enabled="true" />
    </extensions>
    

    您可使用此 XML 檔案註冊繼承自 DeploymentPlanExecutor 的類別。

  7. 將此檔案另存為 %Program Files%\Microsoft Visual Studio 10.0\VSTSDB\Extensions\MyExtensions 資料夾中的 MyDeploymentContributor.extensions.xml。

  8. 關閉 Visual Studio。

    接下來,您會部署資料庫專案以測試參與者。

測試部署參與者

若要測試部署參與者,您必須執行下列工作:

  • 將屬性加入至您打算部署的 .dbproj 檔案

  • 使用 MSBuild 並提供適當參數來部署資料庫專案

將屬性加入至資料庫專案檔 (.dbproj)

如果您要從 MSBuild 使用這個部署參與者,則必須修改資料庫專案,讓使用者能夠透過 MSBuild 傳遞參數。 若要更新資料庫專案,請在您所選擇的編輯器中加以開啟,然後在 .dbproj 檔案中最後一個 </ItemGroup> 節點與最後的 </Project> 節點之間加入下列陳述式:

  <ItemGroup>
    <DeploymentContributorArgument Include="GenerateUpdateReport=$(GenerateUpdateReport)" />
  </ItemGroup>

在更新 .dbproj 檔案後,您就可以使用 MSBuild 傳入命令列建置參數。

部署資料庫專案

若要部署您的資料庫專案並產生部署報告

  1. 開啟 Visual Studio 命令提示字元。 依序按一下 [開始] 功能表、[所有程式]、[Microsoft Visual Studio 2010]、[Visual Studio Tools],然後按一下 [Visual Studio 命令提示字元 (2010)]。

  2. 在命令提示字元中,巡覽至包含資料庫專案的資料夾。

  3. 在命令提示字元中,輸入下列命令列:

    MSBuild /t:Rebuild MyDatabaseProject.dbproj /p:OutDir=.\
    

    以您要建置的資料庫專案名稱取代 MyDatabaseProject。 如果專案自您上次加以建置之後有所變更,您可以使用 /t:Build 而不是 /t:Rebuild。

  4. 在命令提示字元中,輸入下列命令列:

    MSBuild /t:Deploy MyDatabaseProject.dbproj /p:GenerateUpdateReport=true
    

    以您要部署的資料庫專案名稱取代 MyDatabaseProject。

    會出現類似以下的輸出:

Microsoft (R) Build Engine Version 4.0.20817.0
[Microsoft .NET Framework, Version 4.0.20817.0]
Copyright (C) Microsoft Corporation 2007. All rights reserved.

Build started 8/26/2009 3:12:43 PM.
Project "C:\Users\UserName\Documents\Visual Studio 2010\Projects\MyDatabaseProject\Dep
TestToo\MyDatabaseProject.dbproj" on node 1 (Deploy target(s)).
DspDeploy:
  GenerateUpdateReport=true

  Deployment reports ->
  C:\Users\UserName\Documents\Visual Studio 2010\Projects\MyDatabaseProject\MyDatabaseProject\sql\debug\MyTargetDatabase.summary.xml
  C:\Users\UserName\Documents\Visual Studio 2010\Projects\MyDatabaseProject\MyDatabaseProject\sql\debug\MyTargetDatabase.details.xml

  Deployment script generated to:
  C:\Users\UserName\Documents\Visual Studio 2010\Projects\MyDatabaseProject\MyDatabaseProject\sql\debug\MyDatabaseProject.sql

Done Building Project "C:\Users\UserName\Documents\Visual Studio 2010\Projects\MyDatabaseProject\MyDatabaseProject\MyDatabaseProject.dbproj" (Deploy target(s)).


Build succeeded.
    0 Warning(s)
    0 Error(s)

Time Elapsed 00:00:04.02
  1. 開啟 MyTargetDatabase.summary.xml 並檢查內容。

    檔案會與下列顯示新資料庫部署的範例類似:

<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<DeploymentReport>
  <Operations>
    <DeploymentScriptStep />
    <DeploymentScriptDomStep />
    <DeploymentScriptStep />
    <DeploymentScriptDomStep />
    <DeploymentScriptStep />
    <DeploymentScriptStep />
    <DeploymentScriptStep />
    <DeploymentScriptStep />
    <DeploymentScriptDomStep />
    <DeploymentScriptDomStep />
    <DeploymentScriptDomStep />
    <DeploymentScriptDomStep />
    <DeploymentScriptStep />
    <DeploymentScriptDomStep />
    <BeginPreDeploymentScriptStep />
    <DeploymentScriptStep />
    <EndPreDeploymentScriptStep />
    <SqlBeginPreservationStep />
    <SqlEndPreservationStep />
    <SqlBeginDropsStep />
    <SqlEndDropsStep />
    <SqlBeginAltersStep />
    <SqlPrintStep />
    <CreateElementStep Name="Sales" Category="Schema" />
    <SqlPrintStep />
    <CreateElementStep Name="Sales.Customer" Category="Table" />
    <SqlPrintStep />
    <CreateElementStep Name="Sales.PK_Customer_CustID" Category="Primary Key" />
    <SqlPrintStep />
    <CreateElementStep Name="Sales.Orders" Category="Table" />
    <SqlPrintStep />
    <CreateElementStep Name="Sales.PK_Orders_OrderID" Category="Primary Key" />
    <SqlPrintStep />
    <CreateElementStep Name="Sales.Def_Customer_YTDOrders" Category="Default Constraint" />
    <SqlPrintStep />
    <CreateElementStep Name="Sales.Def_Customer_YTDSales" Category="Default Constraint" />
    <SqlPrintStep />
    <CreateElementStep Name="Sales.Def_Orders_OrderDate" Category="Default Constraint" />
    <SqlPrintStep />
    <CreateElementStep Name="Sales.Def_Orders_Status" Category="Default Constraint" />
    <SqlPrintStep />
    <CreateElementStep Name="Sales.FK_Orders_Customer_CustID" Category="Foreign Key" />
    <SqlPrintStep />
    <CreateElementStep Name="Sales.CK_Orders_FilledDate" Category="Check Constraint" />
    <SqlPrintStep />
    <CreateElementStep Name="Sales.CK_Orders_OrderDate" Category="Check Constraint" />
    <SqlPrintStep />
    <CreateElementStep Name="Sales.uspCancelOrder" Category="Procedure" />
    <SqlPrintStep />
    <CreateElementStep Name="Sales.uspFillOrder" Category="Procedure" />
    <SqlPrintStep />
    <CreateElementStep Name="Sales.uspNewCustomer" Category="Procedure" />
    <SqlPrintStep />
    <CreateElementStep Name="Sales.uspPlaceNewOrder" Category="Procedure" />
    <SqlPrintStep />
    <CreateElementStep Name="Sales.uspShowOrderDetails" Category="Procedure" />
    <SqlEndAltersStep />
    <DeploymentScriptStep />
    <BeginPostDeploymentScriptStep />
    <DeploymentScriptStep />
    <EndPostDeploymentScriptStep />
    <DeploymentScriptDomStep />
    <DeploymentScriptDomStep />
    <DeploymentScriptDomStep />
  </Operations>
</DeploymentReport>
注意事項注意事項

如果您部署的資料庫專案與目標資料庫完全相同,產生的報告就沒有什麼意義。 如需更有意義的結果,請對資料庫部署變更或是部署新的資料庫。

  1. 開啟 MyTargetDatabase.details.xml 並檢查內容。

    此詳細資料檔案的小區段顯示用以建立 Sales 結構描述、列印有關建立資料表之訊息,以及建立資料表的項目和指令碼:

    <CreateElementStep Name="Sales" Category="Schema"><![CDATA[CREATE SCHEMA [Sales]
    AUTHORIZATION [dbo];

]]></CreateElementStep>
    <SqlPrintStep><![CDATA[PRINT N'Creating [Sales].[Customer]...';

]]></SqlPrintStep>
    <CreateElementStep Name="Sales.Customer" Category="Table"><![CDATA[CREATE TABLE [Sales].[Customer] (
    [CustomerID]   INT           IDENTITY (1, 1) NOT NULL,
    [CustomerName] NVARCHAR (40) NOT NULL,
    [YTDOrders]    INT           NOT NULL,
    [YTDSales]     INT           NOT NULL
);

]]></CreateElementStep>

藉由在部署計劃執行時分析部署計劃,您可以報告部署中包含的任何資訊,而且可以根據該計劃中的步驟執行其他動作。

後續步驟

您可以建立其他工具來對輸出的 XML 檔案進行處理。 這只是一個 DeploymentPlanExecutor 的範例。 您也可以建立 DeploymentPlanModifier,以在執行部署計劃之前變更部署計劃。

請參閱

概念

擴充 Visual Studio 的資料庫功能

其他資源

使用建置和部署參與者自訂資料庫建置和部署

逐步解說:擴充資料庫專案組建以產生模型統計資料

逐步解說:擴充資料庫專案部署以修改部署計劃