Share via


Exemplarische Vorgehensweise: Erweitern der Bereitstellung von Datenbankprojekten zum Analysieren des Bereitstellungsplans

Sie können Bereitstellungscontributors erstellen, damit beim Bereitstellen eines Datenbankprojekts benutzerdefinierte Aktionen ausgeführt werden. Sie können entweder einen DeploymentPlanModifier oder einen DeploymentPlanExecutor erstellen. Ein DeploymentPlanModifier dient zum Ändern des Plans vor dessen Ausführung. Ein DeploymentPlanExecutor dient zum Ausführen von Vorgängen während der Planausführung. In dieser exemplarischen Vorgehensweise wird ein DeploymentPlanExecutor mit dem Namen "DeploymentUpdateReportContributor" erstellt, durch den ein Bericht zu den Aktionen erstellt wird, die beim Bereitstellen eines Datenbankprojekts ausgeführt werden. Da von diesem Buildcontributor ein Parameter akzeptiert wird, um zu steuern, ob der Bericht generiert wird, ist ein zusätzlicher Schritt erforderlich.

Im Verlauf dieser exemplarischen Vorgehensweise werden die folgenden Hauptaufgaben ausgeführt:

  • Erstellen eines Bereitstellungscontributors vom Typ "DeploymentPlanExecutor"

  • Installieren des Bereitstellungscontributors

  • Testen des Bereitstellungscontributors

Vorbereitungsmaßnahmen

Zum Durchführen dieser exemplarischen Vorgehensweise benötigen Sie die folgenden Komponenten:

  • Installation von Visual Studio 2010 Premium oder Visual Studio 2010 Ultimate auf dem Computer

  • Ein Datenbankprojekt mit Datenbankobjekten

  • Eine Instanz von SQL Server, für die ein Datenbankprojekt bereitgestellt werden kann

Tipp

Diese exemplarische Vorgehensweise richtet sich an Benutzer, die bereits mit den Datenbankfunktionen von Visual Studio vertraut sind. Sie sollten außerdem mit grundlegenden Konzepten von Visual Studio wie dem Erstellen einer Klassenbibliothek und dem Verwenden des Code-Editors zum Hinzufügen von Code zu einer Klasse vertraut sein.

Erstellen eines Bereitstellungscontributors

Führen Sie zum Erstellen eines Bereitstellungscontributors die folgenden Aufgaben aus:

  • Erstellen eines Klassenbibliothekprojekts und Hinzufügen erforderlicher Verweise

  • Definieren einer Klasse mit dem Namen "DeploymentUpdateReportContributor" und Vererbung von DeploymentPlanExecutor

  • Überschreiben der OnPopulateArguments-Methode und der OnExecute-Methode

  • Hinzufügen einer privaten Hilfsklasse

  • Erstellen der resultierenden Assembly

So erstellen Sie ein Klassenbibliotheksprojekt

  1. Erstellen Sie ein Visual Basic- oder ein Visual C#-Klassenbibliothekprojekt mit dem Namen "MyDeploymentContributor".

  2. Klicken Sie im Projektmappen-Explorer mit der rechten Maustaste auf den Ordner Verweise, und klicken Sie anschließend auf Verweis hinzufügen.

  3. Klicken Sie auf die Registerkarte .NET.

  4. Markieren Sie die Einträge Microsoft.Data.Schema und Microsoft.Data.Schema.Sql, und klicken Sie auf OK.

    Fügen Sie der Klasse nun Code hinzu.

So definieren Sie die DeploymentUpdateReportContributor-Klasse

  1. Aktualisieren Sie im Code-Editor die Datei "class1.cs" mit den folgenden using- oder Imports-Anweisungen:

    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. Aktualisieren Sie die Klassendefinition wie folgt:

        [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
    

    Sie haben nun den Buildcontributor definiert und mit dem Attribut angegeben, dass dieser Contributor mit jedem beliebigen Datenbankschema-Anbieter kompatibel ist, der von SqlDatabaseSchemaProvider erbt.

  3. Fügen Sie nun den folgenden Member hinzu, mit dem diesem Anbieter das Akzeptieren eines Befehlszeilenparameters ermöglicht wird:

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

    Dank dieses Members kann der Benutzer mithilfe der Option "GenerateUpdateReport" angeben, ob der Bericht generiert werden soll.

    Im nächsten Schritt wird die OnPopulateArguments-Methode überschrieben, um die Liste mit den Argumenten zu erstellen, die an den Bereitstellungscontributor übergeben werden sollen.

So überschreiben Sie OnPopulateArguments

  • Fügen Sie der DeploymentUpdateReportContributor-Klasse die folgende Überschreibungsmethode hinzu:

        /// <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
    

    Sie erstellen ein ContributorArgumentConfiguration-Objekte und fügen es der Argumentliste hinzu. Standardmäßig wird der Bericht generiert, wenn Sie einen Debugbuild generieren.

    Im nächsten Schritt wird die OnExecute-Methode überschrieben, um den Code hinzuzufügen, der beim Bereitstellen eines Datenbankprojekts ausgeführt werden soll.

So überschreiben Sie OnExecute

  • Fügen Sie der DeploymentUpdateReportContributor-Klasse die folgende Methode hinzu:

        /// <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
    

    An die OnExecute-Methode wird ein DeploymentPlanContributorContext-Objekt übergeben, das den Zugriff auf beliebige angegebene Argumente, auf das Quell- und Zieldatenbankmodell, auf Buildeigenschaften sowie auf Erweiterungsdateien ermöglicht. In diesem Beispiel wird zunächst das Modell abgerufen. Anschließend werden Hilfsfunktionen aufgerufen, um Informationen zum Modell auszugeben. An die Methode wird auch ein ErrorManager übergeben, um die aufgetretenen Fehler zu melden.

    Weitere relevante Typen und Methoden: DataSchemaModel, ModelStore, ModelComparisonResult, DatabaseSchemaProvider, DeploymentPlanHandle and SchemaDeploymentOptions.

    Im nächsten Schritt wird die Hilfsklasse definiert, um in die Details des Bereitstellungsplans vorzudringen.

So fügen Sie die Hilfsklasse hinzu, von der der Hauptteil des Berichts generiert wird

  • Fügen Sie zunächst die Skelette der Hilfsklasse und deren Methoden hinzu, indem Sie den folgenden Code hinzufügen:

            /// <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
    
  • Speichern Sie die Änderungen in der Datei "Class1.cs".

    Fügen Sie als Nächstes die Klassenmember und Methodentexte hinzu.

So fügen Sie die Klassenmember hinzu

  • Fügen Sie der DeploymentReportWriter-Klasse im Code-Editor den folgenden Code hinzu:

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

    Relevante Typen: DataSchemaModel, ModelComparisonResult und DeploymentStep.

    Im nächsten Schritt wird der Text dem Klassenkonstruktor hinzugefügt.

So fügen dem Konstruktor den Methodentext hinzu

  • Fügen Sie den folgenden Code als Konstruktortext hinzu:

                    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
    

    Im nächsten Schritt wird der Methodentext der WriteReport-Methode hinzugefügt.

So fügen Sie den Methodentext der OutputResult-Methode hinzu

  • Fügen Sie den folgenden Code als Text der WriteReport-Methode hinzu:

                    // 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
    

    Relevante Typen: XmlWriter und XmlWriterSettings.

    Im nächsten Schritt wird der Methodentext der ReportPlanOperations-Methode hinzugefügt.

So fügen Sie den Methodentext der ReportPlanOperations-Methode hinzu:

  • Fügen Sie den folgenden Code als Text der ReportPlanOperations-Methode hinzu:

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

    Relevante Typen: DeploymentStep, SqlRenameStep, SqlMoveSchemaStep, SqlTableMigrationStep, CreateElementStep, AlterElementStep und DropElementStep. Weitere Schritttypen, die in diesem Beispiel nicht erläutert wurden: BeginPostDeploymentScriptStep, BeginPreDeploymentScriptStep, DeploymentScriptDomStep, DeploymentScriptStep, EndPostDeploymentScriptStep und EndPreDeploymentScriptStep. Sie können auch nach den SQL Server-spezifischen Schritten suchen: SqlBeginAltersStep, SqlBeginDropsStep, SqlBeginPreservationStep, SqlBeginTransactionStep, SqlEndAltersStep, SqlEndDropsStep, SqlEndPreservationStep, SqlEndTransactionStep, SqlFinalizeDatabaseAccessStep, SqlMoveSchemaStep, SqlPrintStep, SqlRenameStep und SqlTableMigrationStep.

    Im nächsten Schritt wird der Text der GetElementCategory-Methode hinzugefügt.

So fügen Sie den Methodentext der GetElementCategory-Methode hinzu

  • Fügen Sie den folgenden Code als Text der GetElementCategory-Methode hinzu:

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

    Relevante Typen und Methoden: DataSchemaModel, DatabaseSchemaProvider, UserInteractionServices und GetElementTypeDescription.

    Im nächsten Schritt wird der Text der GetElementName-Methode hinzugefügt.

So fügen Sie den Methodentext der GetElementName-Methode hinzu

  • Fügen Sie den folgenden Code als Text der GetElementName-Methode hinzu:

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

    Relevante Typen und Methoden: DataSchemaModel, DatabaseSchemaProvider, UserInteractionServices, GetElementName und ElementNameStyle.

    Speichern Sie die Änderungen an der Klasse. Im nächsten Schritt wird die Klassenbibliothek erstellt.

So signieren und erstellen Sie die Assembly

  1. Klicken Sie im Menü Projekt auf Eigenschaften von MyDeploymentContributor.

  2. Klicken Sie auf die Registerkarte Signierung.

  3. Klicken Sie auf Assembly signieren.

  4. Klicken Sie im Feld Schlüsseldatei mit starkem Namen auswählen auf <Neu>.

  5. Geben Sie im Dialogfeld Schlüssel für einen starken Namen erstellen unter Schlüsseldateiname den Namen MyRefKey ein.

  6. (optional) Sie können für die Schlüsseldatei mit starkem Namen ein Kennwort angeben.

  7. Klicken Sie auf OK.

  8. Klicken Sie im Menü Datei auf Alle speichern.

  9. Klicken Sie im Menü Erstellen auf Projektmappe erstellen.

    Danach müssen Sie die Assembly installieren und registrieren, damit sie geladen wird, wenn Sie Datenbankprojekte bereitstellen.

Installieren eines Bereitstellungscontributors

Führen Sie zum Installieren eines Bereitstellungscontributors die folgenden Aufgaben aus:

  • Kopieren der Assembly und der zugeordneten PDB-Datei in den Ordner "Extensions"

  • Erstellen einer Datei vom Typ "Extensions.xml", um den Bereitstellungscontributor zu registrieren, damit er bei der Bereitstellung von Datenbankprojekten geladen wird

So installieren Sie die Assembly "MyDeploymentContributor"

  1. Erstellen Sie im Verzeichnis "%Programme%\Microsoft Visual Studio 10.0\VSTSDB\Extensions" den Ordner MyExtensions.

  2. Kopieren Sie die signierte Assembly (MyDeploymentContributor.dll) und die zugeordnete PDB-Datei (MyDeploymentContributor.pdb) in den Ordner %Programme%\Microsoft Visual Studio 10.0\VSTSDB\Extensions\MyExtensions.

    Tipp

    Es empfiehlt sich, die XML-Dateien nicht direkt in das Verzeichnis "%Programme%\Microsoft Visual Studio 10.0\VSTSDB\Extensions" zu kopieren. Wenn Sie stattdessen einen Unterordner verwenden, vermeiden Sie versehentliche Änderungen an den anderen Dateien, die mit Visual Studio Premium bereitgestellt werden.

    Im nächsten Schritt muss die Assembly (eine Art Funktionserweiterung) registriert werden, damit sie in Visual Studio Premium angezeigt wird.

So registrieren Sie die Assembly "MyDeploymentContributor"

  1. Klicken Sie im Menü Ansicht auf Weitere Fenster, und klicken Sie anschließend auf Befehlsfenster, um das Befehlsfenster zu öffnen.

  2. Geben Sie im Befehlsfenster folgenden Code ein. Ersetzen Sie FilePath durch den Pfad und Dateinamen der kompilierten DLL-Datei. Schließen Sie Pfad und Dateiname in Anführungszeichen ein.

    Tipp

    Der Pfad der kompilierten DLL-Datei lautet standardmäßig Projektmappenpfad\bin\Debug oder Projektmappenpfad\bin\Release.

    ? System.Reflection.Assembly.LoadFrom(@"FilePath").FullName
    
    ? System.Reflection.Assembly.LoadFrom("FilePath").FullName
    
  3. Drücken Sie die EINGABETASTE.

  4. Kopieren Sie die resultierende Zeile in die Zwischenablage. Die Zeile sollte der folgenden entsprechen:

    "MyDeploymentContributor, Version=1.0.0.0, Culture=neutral, PublicKeyToken=nnnnnnnnnnnnnnnn"
    
  5. Öffnen Sie einen Text-Editor, z. B. Editor.

    Wichtig

    Öffnen Sie den Editor unter Windows Vista und unter Microsoft Windows Server 2008 als Administrator, damit Sie die Datei im Ordner "Programme" speichern können.

  6. Stellen Sie die folgenden Informationen bereit, und geben Sie dabei eigene Werte für Assemblyname, öffentliches Schlüsseltoken und Erweiterungstyp an:

    <?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>
    

    Diese XML-Datei dient zum Registrieren der Klasse, die von DeploymentPlanExecutor erbt.

  7. Speichern Sie die Datei im Verzeichnis "%Programme%\Microsoft Visual Studio 10.0\VSTSDB\Extensions\MyExtensions" als "MyDeploymentContributor.extensions.xml".

  8. Schließen Sie Visual Studio.

    Im nächsten Schritt wird ein Datenbankprojekt bereitgestellt, um den Contributor zu testen.

Testen des Bereitstellungscontributors

Führen Sie zum Testen des Bereitstellungscontributors die folgenden Aufgaben aus:

  • Hinzufügen einer Eigenschaft zur bereitzustellenden DBPROJ-Datei

  • Bereitstellen des Datenbankprojekts mithilfe von MSBuild und Angeben des entsprechenden Parameters

Hinzufügen von Eigenschaften zur Datenbankprojektdatei (DBPROJ-Datei)

Wenn Sie diesen Bereitstellungscontributor mithilfe von MSBuild verwenden möchten, müssen Sie das Datenbankprojekt ändern, um Benutzern das Übergeben eines Parameters mithilfe von MSBuild zu ermöglichen. Um das Datenbankprojekt zu aktualisieren, öffnen Sie diese in einem Editor Ihrer Wahl, und fügen Sie der DBPROJ-Datei die folgenden Anweisungen zwischen dem letzten </ItemGroup>-Knoten in der Datei und dem letzten </Project>-Knoten hinzu:

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

Nach dem Aktualisieren der DBPROJ-Datei können Sie MSBuild verwenden, um die Parameter für Befehlszeilenbuilds zu übergeben.

Bereitstellen des Datenbankprojekts

So können Sie das Datenbankprojekt bereitstellen und einen Bereitstellungsbericht generieren

  1. Öffnen Sie eine Visual Studio-Eingabeaufforderung. Klicken Sie im Startmenü auf Alle Programme, auf Microsoft Visual Studio 2010, auf Visual Studio Tools und anschließend auf Visual Studio-Eingabeaufforderung (2010).

  2. Navigieren Sie an der Eingabeaufforderung zu dem Ordner, der das Datenbankprojekt enthält.

  3. Geben Sie an der Eingabeaufforderung die folgende Befehlszeile ein:

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

    Ersetzen Sie MyDatabaseProject durch den Namen des Datenbankprojekts, das Sie erstellen möchten. Wenn das Projekt seit der letzten Erstellung geändert wurde, können Sie anstelle von "/t:Rebuild" die Option "/t:Build" verwenden.

  4. Geben Sie an der Eingabeaufforderung die folgende Befehlszeile ein:

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

    Ersetzen Sie MyDatabaseProject durch den Namen des Datenbankprojekts, das Sie bereitstellen möchten.

    Die angezeigte Ausgabe ähnelt dem folgenden Beispiel:

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. Öffnen Sie "MyTargetDatabase.summary.xml", und untersuchen Sie den Inhalt.

    Die Datei ähnelt dem folgenden Beispiel, in dem eine neue Datenbankbereitstellung veranschaulicht wird:

<?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>

Tipp

Wenn Sie ein Datenbankprojekt bereitstellen, das mit der Zieldatenbank identisch ist, ist der daraufhin angezeigte Bericht nicht sonderlich aussagekräftig. Stellen Sie zum Erhalten aussagekräftigerer Ergebnisse entweder Änderungen an einer Datenbank oder eine neue Datenbank bereit.

  1. Öffnen Sie MyTargetDatabase.details.xml, und untersuchen Sie den Inhalt.

    Ein kurzer Abschnitt der Detaildatei gibt die Einträge und das Skript zum Erstellen des Schemas Sales, zum Ausgeben einer Meldung zum Erstellen einer Tabelle sowie zum Erstellen der Tabelle an:

    <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>

Durch Analysieren des Bereitstellungsplans während der Ausführung können Berichte zu sämtlichen Informationen erstellt werden, die in der Bereitstellung enthalten sind. Darüber hinaus können weitere Aktionen auf der Grundlage der Schritte in diesem Plan ausgeführt werden.

Nächste Schritte

Sie können weitere Tools erstellen, um die XML-Ausgabedateien zu verarbeiten. Dies ist lediglich ein einzelnes Beispiel für einen DeploymentPlanExecutor. Sie können auch einen DeploymentPlanModifier erstellen, um einen Bereitstellungsplan vor dessen Ausführung zu ändern.

Siehe auch

Konzepte

Erweitern der Datenbankfunktionen von Visual Studio

Weitere Ressourcen

Anpassen von Datenbankbuild und -bereitstellung mithilfe von Build- und Bereitstellungsmitwirkenden

Exemplarische Vorgehensweise: Erweitern des Datenbankprojektbuilds zum Generieren von Modellstatistiken

Exemplarische Vorgehensweise: Erweitern der Bereitstellung von Datenbankprojekten zum Ändern des Bereitstellungsplans