可以在部署 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 方法。 
- 添加专用帮助程序类。 
- 构建生成的程序集。 
创建类库项目
- 创建名为 MyDeploymentContributor 的 Visual Basic 或 C# 类库项目。 
- 将文件“Class1.cs”重命名为“DeploymentUpdateReportContributor.cs”。 
- 在解决方案资源管理器中,右键单击项目节点,然后选择“ 添加引用”。 
- 在“框架”选项卡上选择 System.ComponentModel.Composition 。 
- 添加所需的 SQL 引用:右键单击项目节点,然后选择 “添加引用”。 选择 “浏览 ”并导航到 C:\Program Files (x86)\Microsoft SQL Server\110\DAC\Bin 文件夹。 选择 Microsoft.SqlServer.Dac.dll、 Microsoft.SqlServer.Dac.Extensions.dll和 Microsoft.Data.Tools.Schema.Sql.dll 条目,选择“ 添加”,然后选择“ 确定”。 - 接下来,开始向类添加代码。 
定义部署更新报告贡献者类
- 在代码编辑器中,更新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;
- 更新类定义以匹配以下代码: - /// <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)合并以生成标识符。 
- 接下来,添加用于使此提供程序接受命令行参数的以下成员: - 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 帮助程序方法报告发生的任何错误。 - 其他类型和感兴趣的方法包括: TSqlModel、 ModelComparisonResult、 DeploymentPlanHandle 和 SqlDeploymentOptions。 - 接下来,定义用于深入了解部署计划详细信息的帮助程序类。 
添加生成报表正文的帮助程序类
- 添加以下代码以添加帮助类及其方法: - /// <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) { } }
- 保存对类文件的更改。 辅助类中引用了几种有用的类型: - 代码区域 - 有用类型 - 类成员 - TSqlModel、 ModelComparisonResult、 DeploymentStep - WriteReport 方法 - XmlWriter 和 XmlWriterSettings - ReportPlanOperations 方法 - 感兴趣的类型包括: DeploymentStep、 SqlRenameStep、 SqlMoveSchemaStep、 SqlTableMigrationStep、 CreateElementStep、 AlterElementStep、 DropElementStep。 
 还有其他几个步骤 - 有关完整步骤列表,请参阅 API 文档。- GetElementCategory - TSqlObject - GetElementName - TSqlObject - 接下来,生成类库。 
对程序集进行签名和生成
- 在 “项目 ”菜单上,选择 “MyDeploymentContributor 属性”。 
- 选择“ 签名 ”选项卡。 
- 选择“ 对程序集进行签名”。 
- 在 “选择强名称密钥文件”中,选择“ <新建>”。 
- 在“ 创建强名称密钥 ”对话框中的 “密钥文件名”中,键入 - MyRefKey。
- (可选)可以为强名称密钥文件指定密码。 
- 选择“确定”。 
- 在“文件”菜单上,单击“全部保存”。 
- 在“生成”菜单上,选择“生成解决方案”。 
接下来,必须安装程序集,以便在生成和部署 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\Debug或- YourSolutionPath\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 扩展路径中创建目标文件。
- 请导航至 - %ProgramFiles%\MSBuild
- 创建存储目标文件的新文件夹 - MyContributors。
- 在此目录中创建新文件 - 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>
- 在任何旨在运行贡献者的项目的 - .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 项目并生成部署报告
- 打开 Visual Studio 并打开包含 SQL 项目的解决方案。 
- 选择您的项目并按下“F5”键来执行调试部署。 注意:由于 ContributorArguments 元素仅在配置为“Debug”时才包含,因此现在仅为调试部署生成部署报告。 若要更改此项,请从 ContributorArguments 定义中删除 Condition=“'$(Configuration)' == 'Debug'” 语句。 
- 输出(如以下示例)应出现在输出窗口中: - ------ 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
- 打开 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>- 注释 - 如果部署与目标数据库相同的数据库项目,则生成的报表并不十分有意义。 若要获得更有意义的结果,请将更改部署到数据库或部署新数据库。 
- 打开 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>- 在执行部署计划的过程中,通过分析该计划,可以报告部署中包含的任何信息,并且可以根据该计划中的步骤执行更多操作。