指南:扩展数据库项目部署以分析部署方案

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

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

先决条件

你需要满足以下条件才能完成本演练:

  • 必须已安装包含 SQL Server Data Tools (SSDT) 的 Visual Studio 版本,并支持 C# 或 VB 开发。
  • 必须具有包含 SQL 对象的 SQL 项目。
  • 可将数据库项目部署到的 SQL Server 实例。

注释

本演练适用于已熟悉 SSDT 的 SQL 功能的用户。 你还希望熟悉基本的 Visual Studio 概念,例如如何创建类库,以及如何使用代码编辑器将代码添加到类。

创建部署参与者

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

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

  • 定义从 DeploymentPlanExecutor 继承的名为 DeploymentUpdateReportContributor 的类。

  • 重写 OnExecute 方法。

  • 添加专用帮助程序类。

  • 构建生成的程序集。

创建类库项目

  1. 创建名为 MyDeploymentContributor 的 Visual Basic 或 C# 类库项目。

  2. 将文件“Class1.cs”重命名为“DeploymentUpdateReportContributor.cs”。

  3. 在解决方案资源管理器中,右键单击项目节点,然后选择“ 添加引用”。

  4. 在“框架”选项卡上选择 System.ComponentModel.Composition

  5. 添加所需的 SQL 引用:右键单击项目节点,然后选择 “添加引用”。 选择 “浏览 ”并导航到 C:\Program Files (x86)\Microsoft SQL Server\110\DAC\Bin 文件夹。 选择 Microsoft.SqlServer.Dac.dllMicrosoft.SqlServer.Dac.Extensions.dllMicrosoft.Data.Tools.Schema.Sql.dll 条目,选择“ 添加”,然后选择“ 确定”。

    接下来,开始向类添加代码。

定义部署更新报告贡献者类

  1. 在代码编辑器中,更新DeploymentUpdateReportContributor.cs文件以匹配以下 using 语句:

    using System;
    using System.IO;
    using System.Text;
    using System.Xml;
    using Microsoft.SqlServer.Dac.Deployment;
    using Microsoft.SqlServer.Dac.Extensibility;
    using Microsoft.SqlServer.Dac.Model;
    
  2. 更新类定义以匹配以下代码:

    /// <summary>
        /// An executor that generates a report detailing the steps in the deployment plan. Only runs if a
        /// "GenerateUpdateReport=true" contributor argument is set in the project file, in a targets file or
        /// passed as an additional argument to the DacServices API. To set in a project file, add:
        ///
        /// <PropertyGroup>
        ///     <ContributorArguments Condition="'$(Configuration)' == 'Debug'">
        /// $(ContributorArguments);DeploymentUpdateReportContributor.GenerateUpdateReport=true;
        ///     </ContributorArguments>
        /// <PropertyGroup>
        ///
        /// </summary>
        [ExportDeploymentPlanExecutor("MyDeploymentContributor.DeploymentUpdateReportContributor", "1.0.0.0")]
        public class DeploymentUpdateReportContributor : DeploymentPlanExecutor
        {
        }
    

    现在,您已经定义了一个从 DeploymentPlanExecutor 继承的部署贡献者。 在构建和部署过程中,自定义组件将从标准扩展目录加载。 部署计划执行程序参与者由 ExportDeploymentPlanExecutor 属性标识。

    此属性是必需的,以便可以发现参与者。 它应类似于以下代码:

    [ExportDeploymentPlanExecutor("MyDeploymentContributor.DeploymentUpdateReportContributor", "1.0.0.0")]
    

    在这种情况下,属性的第一个参数应该是唯一标识符 - 用于标识项目文件中的参与者。 最佳做法是将库的命名空间(在本演练中,MyDeploymentContributor)与类名(在本演练中的 DeploymentUpdateReportContributor)合并以生成标识符。

  3. 接下来,添加用于使此提供程序接受命令行参数的以下成员:

    public const string GenerateUpdateReport = "DeploymentUpdateReportContributor.GenerateUpdateReport";
    

    此成员允许用户指定是否应使用 GenerateUpdateReport 选项生成报表。

    接下来,重写 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 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;
    
                ExtensibilityError reportMsg = new ExtensibilityError(msg, Severity.Message);
                base.PublishMessage(reportMsg);
            }
        /// <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 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);
            }
    

    OnExecute 方法传递了 DeploymentPlanContributorContext 对象,该对象提供对任何指定参数、源数据库模型和目标数据库模型、生成属性和扩展文件的访问权限。 在此示例中,我们获取模型,然后调用帮助程序函数来输出有关模型的信息。 我们使用基类上的 PublishMessage 帮助程序方法报告发生的任何错误。

    其他类型和感兴趣的方法包括: TSqlModelModelComparisonResultDeploymentPlanHandleSqlDeploymentOptions

    接下来,定义用于深入了解部署计划详细信息的帮助程序类。

添加生成报表正文的帮助程序类

  • 添加以下代码以添加帮助类及其方法:

    /// <summary>
            /// This class is used to generate a deployment
            /// report.
            /// </summary>
            private class DeploymentReportWriter
            {
                readonly TSqlModel _sourceModel;
                readonly ModelComparisonResult _diff;
                readonly DeploymentStep _planHead;
    
                /// <summary>
                /// The constructor accepts the same context info
                /// that was passed to the OnExecute method of the
                /// deployment contributor.
                /// </summary>
                public DeploymentReportWriter(DeploymentPlanContributorContext context)
                {
                    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;
                }
                /// <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)
                {// 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();
                    }
                }
    
                /// <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)
                {// 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("OriginalName", 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)
                        {
                            using (StringWriter sw = new StringWriter())
                            {
                                currentStep.GenerateBatchScript(sw);
                                string tsqlBody = sw.ToString();
                                if (string.IsNullOrEmpty(tsqlBody) == false)
                                {
                                    xmlw.WriteCData(tsqlBody);
                                }
                            }
                        }
    
                        // close off the current step
                        xmlw.WriteEndElement();
                        currentStep = currentStep.Next;
                    }
                    xmlw.WriteEndElement();
                }
    
                /// <summary>
                /// Returns the category of the specified element
                /// in the source model
                /// </summary>
                private string GetElementCategory(TSqlObject element)
                {
                    return element.ObjectType.Name;
                }
    
                /// <summary>
                /// Returns the name of the specified element
                /// in the source model
                /// </summary>
                private static string GetElementName(TSqlObject element)
                {
                    StringBuilder name = new StringBuilder();
                    if (element.Name.HasExternalParts)
                    {
                        foreach (string part in element.Name.ExternalParts)
                        {
                            if (name.Length > 0)
                            {
                                name.Append('.');
                            }
                            name.AppendFormat("[{0}]", part);
                        }
                    }
    
                    foreach (string part in element.Name.Parts)
                    {
                        if (name.Length > 0)
                        {
                            name.Append('.');
                        }
                        name.AppendFormat("[{0}]", part);
                    }
    
                    return name.ToString();
                }
            }        /// <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)
                {
                }
            }
    
  • 保存对类文件的更改。 辅助类中引用了几种有用的类型:

    代码区域 有用类型
    类成员 TSqlModelModelComparisonResultDeploymentStep
    WriteReport 方法 XmlWriter 和 XmlWriterSettings
    ReportPlanOperations 方法 感兴趣的类型包括: DeploymentStepSqlRenameStepSqlMoveSchemaStepSqlTableMigrationStepCreateElementStepAlterElementStepDropElementStep

    还有其他几个步骤 - 有关完整步骤列表,请参阅 API 文档。
    GetElementCategory TSqlObject
    GetElementName TSqlObject

    接下来,生成类库。

对程序集进行签名和生成

  1. “项目 ”菜单上,选择 “MyDeploymentContributor 属性”。

  2. 选择“ 签名 ”选项卡。

  3. 选择“ 对程序集进行签名”。

  4. “选择强名称密钥文件”中,选择“ <新建>”。

  5. 在“ 创建强名称密钥 ”对话框中的 “密钥文件名”中,键入 MyRefKey

  6. (可选)可以为强名称密钥文件指定密码。

  7. 选择“确定”

  8. 在“文件”菜单上,单击“全部保存”

  9. 在“生成”菜单上,选择“生成解决方案”

接下来,必须安装程序集,以便在生成和部署 SQL 项目时加载该程序集。

安装部署参与者

若要安装部署参与者,必须将程序集和关联 .pdb 文件复制到 Extensions 文件夹。

安装 MyDeploymentContributor 程序集

  • 接下来,将程序集信息复制到 Extensions 目录。 Visual Studio 启动时,它会标识目录和子目录中的任何扩展 %ProgramFiles%\Microsoft SQL Server\110\DAC\Bin\Extensions ,并使它们可供使用:

  • MyDeploymentContributor.dll 程序集文件从输出目录复制到 %ProgramFiles%\Microsoft SQL Server\110\DAC\Bin\Extensions 目录。 默认情况下,已 .dll 编译文件的路径为 YourSolutionPath\YourProjectPath\bin\DebugYourSolutionPath\YourProjectPath\bin\Release

测试您的部署贡献者

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

  • 将属性添加到您计划部署的.sqlproj文件。

  • 使用 MSBuild 部署项目并提供相应的参数。

将属性添加到 SQL 项目 (.sqlproj) 文件

必须始终更新 SQL 项目文件,以指定要运行的参与者的 ID。 此外,由于此参与者需要“GenerateUpdateReport”参数,因此必须将其指定为参与者参数。

您可以通过以下两种方式之一来完成此操作。 可以手动修改 .sqlproj 文件以添加所需的参数。 如果你的参与者没有配置所需的任何参与者参数,或者你不想在大量项目中重复使用参与者,则可以选择这样做。 如果选择此选项,请在文件中第一个导入节点之后将 .sqlproj 以下语句添加到该文件:

<PropertyGroup>
    <DeploymentContributors>$(DeploymentContributors); MyDeploymentContributor.DeploymentUpdateReportContributor</DeploymentContributors>
<ContributorArguments Condition="'$(Configuration)' == 'Debug'">$(ContributorArguments);DeploymentUpdateReportContributor.GenerateUpdateReport=true;</ContributorArguments>
  </PropertyGroup>

第二种方法是创建包含所需参与者参数的目标文件。 如果对多个项目使用相同的参与者,并且需要参与者参数,因为它包含默认值,这非常有用。 在这种情况下,请在 MSBuild 扩展路径中创建目标文件。

  1. 请导航至 %ProgramFiles%\MSBuild

  2. 创建存储目标文件的新文件夹 MyContributors

  3. 在此目录中创建新文件 MyContributors.targets ,向其添加以下文本并保存该文件:

    <?xml version="1.0" encoding="utf-8"?>
    
    <Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
      <PropertyGroup>
    <DeploymentContributors>$(DeploymentContributors);MyDeploymentContributor.DeploymentUpdateReportContributor</DeploymentContributors>
    <ContributorArguments Condition="'$(Configuration)' == 'Debug'">$(ContributorArguments); DeploymentUpdateReportContributor.GenerateUpdateReport=true;</ContributorArguments>
      </PropertyGroup>
    </Project>
    
  4. 在任何旨在运行贡献者的项目的.sqlproj文件内部,通过在文件中<Import Project="$(MSBuildExtensionsPath)\Microsoft\VisualStudio\v$(VisualStudioVersion)\SSDT\Microsoft.Data.Tools.Schema.SqlTasks.targets" />节点之后添加以下语句到.sqlproj文件中,导入目标文件。

    <Import Project="$(MSBuildExtensionsPath)\MyContributors\MyContributors.targets " />
    

遵循上述方法之一后,可以使用 MSBuild 传入命令行生成的参数。

注释

必须始终更新“DeploymentContributors”属性以指定参与者 ID。 这是贡献者源文件中“ExportDeploymentPlanExecutor”属性所使用的相同 ID。 如果没有这个,则在构建项目时不会运行贡献模块。 仅当您有参与者需要的参数才能运行时,才需更新“ContributorArguments”属性。

部署数据库项目

项目可以在 Visual Studio 中按正常方式发布或部署。 打开包含 SQL 项目的解决方案,然后从项目的右键菜单中选择“发布...”选项,或按 F5 将项目调试部署到 LocalDB。 在此示例中,我们使用“发布...”用于生成部署脚本的对话框。

部署 SQL 项目并生成部署报告

  1. 打开 Visual Studio 并打开包含 SQL 项目的解决方案。

  2. 选择您的项目并按下“F5”键来执行调试部署。 注意:由于 ContributorArguments 元素仅在配置为“Debug”时才包含,因此现在仅为调试部署生成部署报告。 若要更改此项,请从 ContributorArguments 定义中删除 Condition=“'$(Configuration)' == 'Debug'” 语句。

  3. 输出(如以下示例)应出现在输出窗口中:

    ------ Deploy started: Project: Database1, Configuration: Debug Any CPU ------
    Finished verifying cached model in 00:00:00
    Deployment reports ->
    
      C:\Users\UserName\Documents\Visual Studio 2012\Projects\MyDatabaseProject\MyDatabaseProject\sql\debug\MyTargetDatabase.summary.xml
      C:\Users\UserName\Documents\Visual Studio 2012\Projects\MyDatabaseProject\MyDatabaseProject\sql\debug\MyTargetDatabase.details.xml
    
      Deployment script generated to:
      C:\Users\UserName\Documents\Visual Studio 2012\Projects\MyDatabaseProject\MyDatabaseProject\sql\debug\MyDatabaseProject.sql
    
  4. 打开 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>
    

    注释

    如果部署与目标数据库相同的数据库项目,则生成的报表并不十分有意义。 若要获得更有意义的结果,请将更改部署到数据库或部署新数据库。

  5. 打开 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>
    

    在执行部署计划的过程中,通过分析该计划,可以报告部署中包含的任何信息,并且可以根据该计划中的步骤执行更多操作。