演练:扩展数据库项目部署以分析部署计划

可以创建部署参与者,以在部署数据库项目时执行自定义操作。 可以创建 DeploymentPlanModifier 或 DeploymentPlanExecutor。 使用 DeploymentPlanModifier 可在执行计划前更改计划,使用 DeploymentPlanExecutor 可在执行计划期间执行操作。 在本演练中,您将创建一个名为 DeploymentUpdateReportContributor 的 DeploymentPlanExecutor,用于创建有关在部署数据库项目时执行的操作的报告。 因为此生成参与者接受用于控制是否生成报告的参数,所以必须执行一个附加步骤。

在本演练中,您将完成以下主要任务:

  • 创建 DeploymentPlanExecutor 类型的部署参与者

  • 安装部署参与者

  • 测试部署参与者

系统必备

您需要以下组件来完成本演练:

  • 在计算机上安装 Visual Studio 2010 高级专业版 或 Visual Studio 2010 旗舰版。

  • 包含数据库对象的数据库项目

  • 可以向其部署数据库项目的 SQL Server 实例

提示

本演练专供已熟悉 Visual Studio 数据库功能的用户使用。 同时,您还应熟悉基本的 Visual Studio 概念,例如如何创建类库以及如何使用代码编辑器向类添加代码。

创建部署参与者

若要创建部署参与者,必须执行以下任务:

  • 创建类库项目并添加所需引用

  • 定义一个名为 DeploymentUpdateReportContributor 的类,该类继承自 DeploymentPlanExecutor

  • 重写 OnPopulateArguments 和 OnExecute 方法。

  • 添加私有帮助器类

  • 生成结果程序集

创建类库项目

  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 对象,该对象提供对任何指定参数、源和目标数据库模型、生成属性和扩展文件的访问。 在此示例中,我们获取模型,然后调用帮助器函数以输出有关模型的信息。 还会向该方法传递一个 ErrorManager,用于报告发生的任何错误。

    其他相关类型和方法包括:DataSchemaModelModelStoreModelComparisonResultDatabaseSchemaProviderDeploymentPlanHandleSchemaDeploymentOptions

    接下来,定义挖掘部署计划详细信息的帮助器类。

添加生成报告主体的帮助器类

  • 首先,通过添加下面的代码来添加帮助器类及其方法的主干:

            /// <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 高级专业版提供的其他文件。

    接下来,必须注册程序集(即,某种类型的功能扩展),以便在 Visual Studio 高级专业版中显示该程序集。

注册 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 工具”“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 的数据库功能

其他资源

使用生成参与者和部署参与者自定义数据库生成和部署

演练:扩展数据库项目生成以生成模型统计信息

演练:扩展数据库项目部署以修改部署计划