다음을 통해 공유


연습: 데이터베이스 프로젝트 배포를 확장하여 배포 계획 분석

SQL 프로젝트를 배포할 때 사용자 지정 작업을 수행하는 배포 기여자를 만들 수 있습니다. 배포 참가자는 DeploymentPlanModifier 또는 DeploymentPlanExecutor 중에서 만들 수 있습니다. DeploymentPlanModifier를 사용하면 계획을 실행하기 전에 항목을 변경할 수 있고 DeploymentPlanExecutor를 사용하면 계획을 실행하는 동안 작업을 수행할 수 있습니다. 이 연습에서는 데이터베이스 프로젝트를 배포할 때 수행되는 작업에 대한 보고서를 만드는 DeploymentUpdateReportContributor라는 이름의 DeploymentPlanExecutor를 만듭니다. 이 빌드 참가자는 보고서가 생성되는지 여부를 제어하기 위한 매개 변수를 받기 때문에 추가 필수 단계를 수행해야 합니다.

이 연습에서 수행하는 주요 작업은 다음과 같습니다.

필수 조건

이 연습을 완료하려면 다음과 같은 구성 요소가 필요합니다.

  • SQL Server Data Tools(SSDT)가 포함되고 C# 또는 VB 개발이 지원되는 Visual Studio 버전이 설치되어 있어야 합니다.

  • SQL 개체가 포함된 SQL 프로젝트가 있어야 합니다.

  • 데이터베이스 프로젝트를 배포할 수 있는 SQL Server의 인스턴스가 필요합니다.

참고 항목

이 연습은 SSDT의 SQL 기능에 이미 익숙한 사용자를 위한 것입니다. 또한 클래스 라이브러리를 만드는 방법 및 코드 편집기를 사용하여 클래스에 코드를 추가하는 방법과 같은 기본 Visual Studio 개념을 잘 알고 있어야 합니다.

배포 기여자 만들기

배포 기여자를 만들려면 다음 작업을 수행해야 합니다.

  • 클래스 라이브러리 프로젝트를 만들고 필요한 참조를 추가합니다.

  • DeploymentPlanExecutor에서 상속하는 DeploymentUpdateReportContributor라는 클래스를 정의합니다.

  • OnExecute 메서드를 재정의합니다.

  • 비공개 도우미 클래스를 추가합니다.

  • 결과 어셈블리를 빌드합니다.

클래스 라이브러리 프로젝트를 만들려면

  1. MyDeploymentContributor라는 Basic 또는 C# 클래스 라이브러리 프로젝트를 만듭니다.

  2. 파일 이름을 "Class1.cs"에서 "DeploymentUpdateReportContributor.cs"로 바꿉니다.

  3. 솔루션 탐색기에서 프로젝트 노드를 마우스 오른쪽 단추로 클릭한 다음 참조 추가를 클릭합니다.

  4. [프레임워크] 탭에서 System.ComponentModel.Composition을 선택합니다.

  5. 필요한 SQL 참조 추가: 프로젝트 노드를 마우스 오른쪽 단추로 클릭한 다음 참조 추가를 클릭합니다. Browse를 클릭하고 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 클래스를 정의하려면

  1. 코드 편집기에서 다음 using 문과 일치하도록 DeploymentUpdateReportContributor.cs 파일을 업데이트합니다.

    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. Will only run  
        /// 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 the following:  
        ///   
        /// <PropertyGroup>  
        ///     <ContributorArguments Condition="'$(Configuration)' == 'Debug'">  
        /// $(ContributorArguments);DeploymentUpdateReportContributor.GenerateUpdateReport=true;  
        ///     </ContributorArguments>  
        /// <PropertyGroup>  
        ///   
        /// </summary>  
        [ExportDeploymentPlanExecutor("MyDeploymentContributor.DeploymentUpdateReportContributor", "1.0.0.0")]  
        public class DeploymentUpdateReportContributor : DeploymentPlanExecutor  
        {  
        }  
    
    

    이제 DeploymentPlanExecutor에서 상속되는 배포 기여자를 정의했습니다. 빌드 및 배포 프로세스 중에 사용자 지정 기여자는 표준 확장 디렉터리에서 로드됩니다. 배포 계획 Executor 참가자는 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 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;  
    
                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 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);  
            }  
    

    OnExecute 메서드는 지정된 인수, 원본 및 대상 데이터베이스 모델, 빌드 속성 및 확장 파일에 대한 액세스를 제공하는 DeploymentPlanContributorContext 개체를 전달합니다. 이 예제에서는 모델을 가져와 도우미 함수를 호출하여 모델에 대한 정보를 출력합니다. 기본 클래스에서 PublishMessage 도우미 메서드를 사용하여 발생한 모든 오류를 보고합니다.

    추가적인 관심 형식 및 메서드에는 TSqlModel, ModelComparisonResult, DeploymentPlanHandleSqlDeploymentOptions 등이 있습니다.

    다음으로 배포 계획의 세부 정보를 자세히 살펴보는 도우미 클래스를 정의합니다.

보고서 본문을 생성하는 도우미 클래스를 추가하려면

  • 다음 코드를 추가하여 도우미 클래스 및 해당 메서드를 추가합니다.

    /// <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("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)  
                        {  
                            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

    다음으로 클래스 라이브러리를 빌드합니다.

어셈블리에 서명하고 빌드하려면

  1. 프로젝트 메뉴에서 MyDeploymentContributor 속성을 클릭합니다.

  2. 시그니처 탭을 클릭합니다.

  3. 어셈블리에 서명을 클릭합니다.

  4. 강력한 이름 키 파일 선택에서 <새로 만들기>를 클릭합니다.

  5. 강력한 이름 키 만들기 대화 상자에서 키 파일 이름MyRefKey를 입력합니다.

  6. (선택 사항)강력한 이름 키 파일의 암호를 지정할 수 있습니다.

  7. 확인을 클릭합니다.

  8. 파일 메뉴에서 모두 저장을 클릭합니다.

  9. 빌드 메뉴에서 솔루션 빌드를 클릭합니다.

그런 다음 SQL 프로젝트를 빌드 및 배포할 때 로드되도록 어셈블리를 설치해야 합니다.

배포 기여자 설치

배포 기여자를 설치하려면 어셈블리 및 연관된 .pdb 파일을 Extensions 폴더에 복사해야 합니다.

MyDeploymentContributor 어셈블리를 설치하려면

  • 다음으로 어셈블리 정보를 확장 디렉터리에 복사합니다. Visual Studio가 시작되면 %Program Files%\Microsoft SQL Server\110\DAC\Bin\Extensions 디렉터리 및 하위 디렉터리에서 확장을 식별하고 이를 사용할 수 있도록 설정합니다.

  • 출력 디렉터리에서 %Program Files%\Microsoft SQL Server\110\DAC\Bin\Extensions 디렉터리로 MyDeploymentContributor.dll 어셈블리 파일을 복사합니다. 기본적으로 컴파일된 .dll 파일의 경로는 YourSolutionPath\YourProjectPath\bin\Debug 또는 YourSolutionPath\YourProjectPath\bin\Release입니다.

배포 기여자 테스트

배포 기여자를 테스트하려면 다음 작업을 수행해야 합니다.

  • 배포하려는 .sqlproj 파일에 속성을 추가합니다.

  • MSBuild를 사용하고 적절한 매개 변수를 제공하여 프로젝트를 배포합니다.

SQL 프로젝트(.sqlproj) 파일에 속성 추가

실행하려는 기여자 ID를 지정하려면 항상 SQL 프로젝트 파일을 업데이트해야 합니다. 또한 이 기여자는 "GenerateUpdateReport" 인수를 예상하므로 기여자 인수로 지정되어야 합니다.

다음 두 가지 방법 중 하나를 사용합니다. .sqlproj 파일을 수동으로 수정해서 필요한 인수를 추가할 수 있습니다. 참가자가 구성에 필요한 검토 인수를 포함하지 않는 경우 또는 대량의 프로젝트에서 참가자를 다시 사용하지 않으려는 경우에는 이 작업을 선택해서 수행할 수 있습니다. 이 옵션을 선택할 경우, .sqlproj 파일에서 파일의 첫 번째 가져오기 노드 다음에 다음 문을 추가합니다.

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

두 번째 방법은 필요한 기여자 인수를 포함하는 대상 파일을 만드는 것입니다. 이는 기본값을 포함하므로 여러 프로젝트에 동일한 기여자를 사용하고 필요한 기여자 인수를 갖고 있는 경우에 유용합니다. 이 경우 MSBuild 확장 경로에 대상 파일을 만듭니다.

  1. %Program Files%\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” /> 노드 뒤에 다음 문을 추가하여 대상 파일을 가져옵니다.

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

이러한 방법 중 하나를 수행한 후에는 MSBuild를 사용하여 명령줄 빌드에 대한 매개 변수를 전달할 수 있습니다.

참고 항목

기여자 ID를 지정하려면 항상 "DeploymentContributors" 속성을 업데이트해야 합니다. 이 ID는 기여자 원본 파일에서 “ExportDeploymentPlanExecutor” 특성에 사용된 것과 동일한 ID입니다. 이 ID가 없으면 프로젝트를 빌드할 때 참가자가 실행되지 않습니다. "ContributorArguments" 속성은 실행할 참가자에 필요한 인수가 있는 경우에만 업데이트해야 합니다.

데이터베이스 프로젝트 배포

프로젝트는 Visual Studio 내에서 일반적으로 게시 및 배포할 수 있습니다. SQL 프로젝트가 포함된 솔루션을 열고 "게시..."를 선택하기만 하면 됩니다. 옵션: 프로젝트의 상황에 맞는 메뉴를 마우스 오른쪽 단추로 클릭하거나 LocalDB에 디버그 배포를 위해서는 F5를 사용합니다. 이 예에서는 “게시...” 대화 상자를 사용하여 배포 스크립트를 생성합니다.

SQL 프로젝트를 배포하고 배포 보고서를 생성하려면
  1. Visual Studio를 열고 SQL 프로젝트가 포함된 솔루션을 엽니다.

  2. 프로젝트를 선택하고 "F5"를 눌러 디버그 배포를 수행합니다. 참고: ContributorArguments 요소는 구성이 “디버그”인 경우에만 포함되도록 설정되었으므로, 현재는 배포 보고서가 디버그 배포용으로만 생성됩니다. 이를 변경하려면 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>  
    
    

    배포 계획이 실행될 때 분석하여 배포에 포함된 모든 정보를 보고하고 해당 계획의 단계에 따라 추가 작업을 수행할 수 있습니다.

다음 단계

출력 XML 파일의 처리를 수행하기 위한 추가 도구를 만들 수도 있습니다. 이는 DeploymentPlanExecutor의 한 가지 예제일 뿐입니다. DeploymentPlanModifier를 만들어 배포 계획을 실행하기 전에 변경할 수도 있습니다.

참고 항목

연습: 데이터베이스 프로젝트 빌드를 확장하여 모델 통계 생성
연습: 데이터베이스 프로젝트 배포를 확장하여 배포 계획 수정
빌드 및 배포 기여자를 사용하여 데이터베이스 빌드 및 배포 사용자 지정