Megosztás a következőn keresztül:


Útmutató: Az adatbázisprojekt üzembe helyezésének kiterjesztése az üzembehelyezési terv módosításához

Sql-projekt üzembe helyezésekor üzembe helyezési közreműködőket hozhat létre egyéni műveletek végrehajtásához. Létrehozhat vagy egy DeploymentPlanModifier, vagy egy DeploymentPlanExecutor. A DeploymentPlanModifier használatával módosíthatja a tervet a végrehajtás előtt, a DeploymentPlanExecutor pedig műveleteket hajthat végre a terv végrehajtása közben. Ebben az útmutatóban egy SqlRestartableScriptContributor nevű DeploymentPlanModifier hozol létre. A DeploymentPlanModifier SqlRestartableScriptContributor az üzembehelyezési szkript kötegeihez hozzáadJA az IF utasításokat, hogy a szkript újrafuthasson, amíg el nem fejeződik, ha hiba történik a végrehajtás során.

Ebben az útmutatóban a következő főbb feladatokat hajtja végre:

Előfeltételek

Az útmutató elvégzéséhez a következő összetevőkre van szüksége:

  • Telepítenie kell a Visual Studio olyan verzióját, amely tartalmazza az SQL Server Data Toolst, és támogatja a C#-fejlesztést.

  • Sql-objektumokat tartalmazó SQL-projektnek kell lennie.

  • Az SQL Server egy példánya, amelyen adatbázisprojektet helyezhet üzembe.

Jegyzet

Ez az útmutató olyan felhasználók számára készült, akik már ismerik az SQL Server Data Tools SQL-funkcióit. Emellett ismernie kell az alapvető Visual Studio-fogalmakat is, például az osztálytárak létrehozását, valamint azt, hogy a kódszerkesztővel hogyan adhat hozzá kódot egy osztályhoz.

Üzembehelyezési közreműködő létrehozása

Üzembe helyezési közreműködő létrehozásához a következő feladatokat kell elvégeznie:

  • Hozzon létre egy osztálytárprojektet, és adjon hozzá szükséges hivatkozásokat.

  • Definiáljon egy SqlRestartableScriptContributor nevű osztályt, amely örökli DeploymentPlanModifier.

  • Bírálja felül az OnExecute metódust.

  • Privát segítő módszerek hozzáadása.

  • Hozza létre az eredményként kapott szerelvényt.

Osztálytárprojekt létrehozása

  1. Hozzon létre egy MyOtherDeploymentContributor nevű C#-osztálykódtárat (.NET-keretrendszer).

  2. Nevezze át a "Class1.cs" fájlt "SqlRestartableScriptContributor.cs" névre.

  3. A Megoldáskezelőben kattintson a jobb gombbal a projektcsomópontra, majd kattintson Hivatkozás hozzáadásaparancsra.

  4. Válassza System.ComponentModel.Composition a Keretrendszerek lapon.

  5. A Project menüjében válassza a NuGet-csomagok kezelése lehetőséget. Telepítse a Microsoft.SqlServer.DacFx legújabb stabil kiadásait.

Ezután kezdje el hozzáadni a kódot az osztályhoz.

Az SqlRestartableScriptContributor osztály definiálása

  1. A kódszerkesztőben frissítse a class1.cs fájlt, hogy megfeleljen a következő használatával készült utasításoknak.

    using System;  
    using System.Collections.Generic;  
    using System.Globalization;  
    using System.Text;  
    using Microsoft.SqlServer.Dac.Deployment;  
    using Microsoft.SqlServer.Dac.Model;  
    using Microsoft.SqlServer.TransactSql.ScriptDom;  
    
  2. Frissítse az osztálydefiníciót az alábbi példának megfelelően:

        /// <summary>  
    /// This deployment contributor modifies a deployment plan by adding if statements  
    /// to the existing batches in order to make a deployment script able to be rerun to completion  
    /// if an error is encountered during execution  
    /// </summary>  
    [ExportDeploymentPlanModifier("MyOtherDeploymentContributor.RestartableScriptContributor", "1.0.0.0")]  
    public class SqlRestartableScriptContributor : DeploymentPlanModifier  
    {  
    }  
    
    

    Most már definiálta az üzembehelyezési hozzájárulót, amely örököl a DeploymentPlanModifierosztályból. A buildelési és üzembehelyezési folyamatok során az egyéni közreműködők egy szabványos bővítménykönyvtárból töltődnek be. Az üzembehelyezési tervet módosító közreműködők egy ExportDeploymentPlanModifier attribútummal vannak azonosítva. Ez az attribútum szükséges a közreműködők felderítéséhez. Ennek az attribútumnak a következő függvény-dekorátorhoz hasonlóan kell kinéznie:

    [ExportDeploymentPlanModifier("MyOtherDeploymentContributor.RestartableScriptContributor", "1.0.0.0")]  
    
    
  3. Adja hozzá a következő tagdeklarációkat:

         private const string BatchIdColumnName = "BatchId";  
            private const string DescriptionColumnName = "Description";  
    
            private const string CompletedBatchesVariableName = "CompletedBatches";  
            private const string CompletedBatchesVariable = "$(CompletedBatches)";  
            private const string CompletedBatchesSqlCmd = @":setvar " + CompletedBatchesVariableName + " __completedBatches_{0}_{1}";  
            private const string TotalBatchCountSqlCmd = @":setvar TotalBatchCount {0}";  
            private const string CreateCompletedBatchesTable = @"  
    if OBJECT_ID(N'tempdb.dbo." + CompletedBatchesVariable + @"', N'U') is null  
    begin  
    use tempdb  
    create table [dbo].[$(CompletedBatches)]  
    (  
    BatchId int primary key,  
    Description nvarchar(300)  
    )  
    use [$(DatabaseName)]  
    end  
    ";  
    
    

    Ezután felülbírálja az OnExecute metódust, hogy hozzáadja az adatbázisprojekt üzembe helyezésekor futtatni kívánt kódot.

Az OnExecute felülbírálása

  1. Adja hozzá a következő metódust az SqlRestartableScriptContributor osztályhoz:

    /// <summary>  
    /// You override the OnExecute method to do the real work of the contributor.  
    /// </summary>  
    /// <param name="context"></param>  
    protected override void OnExecute(DeploymentPlanContributorContext context)  
    {  
         // Replace this with the method body  
    }  
    
    

    Ön felülbírálja az OnExecute metódust az alaposztály, a DeploymentPlanContributoresetében. DeploymentPlanContributorDeploymentPlanModifier és DeploymentPlanExecutoralaposztálya. A rendszer egy DeploymentPlanContributorContext objektumot ad át az OnExecute metódusnak, amely hozzáférést biztosít a megadott argumentumokhoz, a cél forrás- és adatbázismodelljeihez, az üzembehelyezési tervhez és az üzembe helyezési beállításokhoz. Ebben a példában lekérjük az üzembehelyezési tervet és a céladatbázis nevét.

  2. Most adja hozzá a törzs kezdeteit az OnExecute metódushoz:

    // Obtain the first step in the Plan from the provided context  
    DeploymentStep nextStep = context.PlanHandle.Head;  
    int batchId = 0;  
    BeginPreDeploymentScriptStep beforePreDeploy = null;  
    
    // Loop through all steps in the deployment plan  
    while (nextStep != null)  
    {  
        // Increment the step pointer, saving both the current and next steps  
        DeploymentStep currentStep = nextStep;  
        nextStep = currentStep.Next;  
    
        // Add additional step processing here  
    }  
    
    // if we found steps that required processing, set up a temporary table to track the work that you are doing  
    if (beforePreDeploy != null)  
    {  
        // Add additional post-processing here  
    }  
    
    // Cleanup and drop the table   
    DeploymentScriptStep dropStep = new DeploymentScriptStep(DropCompletedBatchesTable);  
    base.AddAfter(context.PlanHandle, context.PlanHandle.Tail, dropStep);  
    
    

    Ebben a kódban meghatározunk néhány helyi változót, és beállítjuk azt a hurkot, amely az üzembe helyezési terv összes lépésének feldolgozását kezeli. A ciklus befejeződése után el kell végeznünk néhány utófeldolgozást, majd elvetjük az üzembe helyezés során létrehozott ideiglenes táblát, hogy nyomon követjük a terv végrehajtásának előrehaladását. A legfontosabb típusok a következők: DeploymentStep és DeploymentScriptStep. A kulcsmetódus az AddAfter.

  3. Most adja hozzá a további lépésfeldolgozást, és cserélje le a "További lépésfeldolgozás hozzáadása itt" című megjegyzést:

    // Look for steps that mark the pre/post deployment scripts  
    // These steps will always be in the deployment plan even if the  
    // user's project does not have a pre/post deployment script  
    if (currentStep is BeginPreDeploymentScriptStep)  
    {  
        // This step marks the beginning of the predeployment script.  
        // Save the step and move on.  
        beforePreDeploy = (BeginPreDeploymentScriptStep)currentStep;  
        continue;  
    }  
    if (currentStep is BeginPostDeploymentScriptStep)  
    {  
        // This is the step that marks the beginning of the post deployment script.    
        // We do not continue processing after this point.  
        break;  
    }  
    if (currentStep is SqlPrintStep)  
    {  
        // We do not need to put if statements around these  
        continue;  
    }  
    
    // if we have not yet found the beginning of the pre-deployment script steps,   
    // skip to the next step.  
    if (beforePreDeploy == null)  
    {  
        // We only surround the "main" statement block with conditional  
        // statements  
        continue;  
    }  
    
    // Determine if this is a step that we need to surround with a conditional statement  
    DeploymentScriptDomStep domStep = currentStep as DeploymentScriptDomStep;  
    if (domStep == null)  
    {  
        // This step is not a step that we know how to modify,  
        // so skip to the next step.  
        continue;  
    }  
    
    TSqlScript script = domStep.Script as TSqlScript;  
    if (script == null)  
    {  
        // The script dom step does not have a script with batches - skip  
        continue;  
    }  
    
        // Loop through all the batches in the script for this step.  All the statements  
        // in the batch will be enclosed in an if statement that will check the  
        // table to ensure that the batch has not already been executed  
        TSqlObject sqlObject;  
        string stepDescription;  
        GetStepInfo(domStep, out stepDescription, out sqlObject);  
        int batchCount = script.Batches.Count;  
    
    for (int batchIndex = 0; batchIndex < batchCount; batchIndex++)  
    {  
        // Add batch processing here  
    }  
    
    

    A kód megjegyzései ismertetik a feldolgozást. Áttekintő szinten ez a kód megkeresi a számodra fontos lépéseket, kihagyja a többit, és megáll, amikor elérkezik az üzembe helyezés utáni lépések kezdetéhez. Ha a lépés olyan utasításokat tartalmaz, amelyeket feltételesekkel kell körülvennünk, további feldolgozást hajtunk végre. Kulcstípusok, metódusok és tulajdonságok a DacFx-kódtár alábbi összetevőit tartalmazzák: BeginPreDeploymentScriptStep, BeginPostDeploymentScriptStep, TSqlObject, TSqlScript, Script, DeploymentScriptDomStepés SqlPrintStep.

  4. Most adja hozzá a kötegfeldolgozó kódot a "Kötegfeldolgozás hozzáadása itt" című megjegyzés helyére:

        // Create the if statement that will contain the batch's contents  
        IfStatement ifBatchNotExecutedStatement = CreateIfNotExecutedStatement(batchId);  
        BeginEndBlockStatement statementBlock = new BeginEndBlockStatement();  
        ifBatchNotExecutedStatement.ThenStatement = statementBlock;  
        statementBlock.StatementList = new StatementList();  
    
        TSqlBatch batch = script.Batches[batchIndex];  
        int statementCount = batch.Statements.Count;  
    
        // Loop through all statements in the batch, embedding those in an sp_execsql  
        // statement that must be handled this way (schemas, stored procedures,   
        // views, functions, and triggers).  
        for (int statementIndex = 0; statementIndex < statementCount; statementIndex++)  
        {  
            // Add additional statement processing here  
        }  
    
        // Add an insert statement to track that all the statements in this  
        // batch were executed.  Turn on nocount to improve performance by  
        // avoiding row inserted messages from the server  
        string batchDescription = string.Format(CultureInfo.InvariantCulture,  
            "{0} batch {1}", stepDescription, batchIndex);  
    
        PredicateSetStatement noCountOff = new PredicateSetStatement();  
        noCountOff.IsOn = false;  
        noCountOff.Options = SetOptions.NoCount;  
    
        PredicateSetStatement noCountOn = new PredicateSetStatement();  
        noCountOn.IsOn = true;  
        noCountOn.Options = SetOptions.NoCount;   
        InsertStatement batchCompleteInsert = CreateBatchCompleteInsert(batchId, batchDescription);  
        statementBlock.StatementList.Statements.Add(noCountOn);  
    statementBlock.StatementList.Statements.Add(batchCompleteInsert);  
        statementBlock.StatementList.Statements.Add(noCountOff);  
    
        // Remove all the statements from the batch (they are now in the if block) and add the if statement  
        // as the sole statement in the batch  
        batch.Statements.Clear();  
        batch.Statements.Add(ifBatchNotExecutedStatement);  
    
        // Next batch  
        batchId++;  
    
    

    Ez a kód létrehoz egy HA utasítást egy BEGIN/END blokktal együtt. Ezután további feldolgozást hajtunk végre a csomagban lévő nyilatkozatokon. Ha ez befejeződött, hozzáadunk egy INSERT utasítást, amely információkat ad hozzá az ideiglenes táblához, amely nyomon követi a szkript végrehajtásának előrehaladását. Végül frissítse a köteget, és cserélje le a korábban ott lévő utasításokat az új IF-re, amely a korábbi utasításokat tartalmazza. A legfontosabb típusok, módszerek és tulajdonságok a következők: IfStatement, BeginEndBlockStatement, StatementList, TSqlBatch, PredicateSetStatement, SetOptionsés InsertStatement.

  5. Most adja hozzá az utasításfeldolgozási ciklus törzsét. Cserélje le a "További utasításfeldolgozás hozzáadása itt" szöveget tartalmazó megjegyzést:

    TSqlStatement smnt = batch.Statements[statementIndex];  
    
    if (IsStatementEscaped(sqlObject))  
    {  
        // "escape" this statement by embedding it in a sp_executesql statement  
        string statementScript;  
        domStep.ScriptGenerator.GenerateScript(smnt, out statementScript);  
        ExecuteStatement spExecuteSql = CreateExecuteSql(statementScript);  
        smnt = spExecuteSql;  
    }  
    
    statementBlock.StatementList.Statements.Add(smnt);  
    
    

    A köteg minden utasítása esetében, ha az utasítás olyan típusú, amelyet sp_executesql utasítással kell becsomagolni, módosítsa az utasítást ennek megfelelően. A kód ezután hozzáadja az utasítást a létrehozott BEGIN/END blokk utasításlistájához. A kulcstípusok, metódusok és tulajdonságok közé tartozik TSqlStatement és ExecuteStatement.

  6. Végül adja hozzá a feldolgozás utáni szakaszt a "További feldolgozás hozzáadása itt" című megjegyzés helyett:

    // Declare a SqlCmd variables.  
    //  
    // CompletedBatches variable - defines the name of the table in tempdb that will track  
    // all the completed batches.  The temporary table's name has the target database name and  
    // a guid embedded in it so that:  
    // * Multiple deployment scripts targeting different DBs on the same server  
    // * Failed deployments with old tables do not conflict with more recent deployments  
    //  
    // TotalBatchCount variable - the total number of batches surrounded by if statements.  Using this  
    // variable pre/post deployment scripts can also use the CompletedBatches table to make their  
    // script rerunnable if there is an error during execution  
    StringBuilder sqlcmdVars = new StringBuilder();  
    sqlcmdVars.AppendFormat(CultureInfo.InvariantCulture, CompletedBatchesSqlCmd,  
        context.Options.TargetDatabaseName, Guid.NewGuid().ToString("D"));  
    sqlcmdVars.AppendLine();  
    sqlcmdVars.AppendFormat(CultureInfo.InvariantCulture, TotalBatchCountSqlCmd, batchId);  
    
    DeploymentScriptStep completedBatchesSetVarStep = new DeploymentScriptStep(sqlcmdVars.ToString());  
    base.AddBefore(context.PlanHandle, beforePreDeploy, completedBatchesSetVarStep);  
    
    // Create the temporary table we will use to track the work that we are doing  
    DeploymentScriptStep createStatusTableStep = new DeploymentScriptStep(CreateCompletedBatchesTable);  
    base.AddBefore(context.PlanHandle, beforePreDeploy, createStatusTableStep);  
    
    

    Ha a feldolgozás egy vagy több, feltételes utasítással körülvett lépést talált, az SQLCMD-változók definiálásához utasításokat kell hozzáadni az üzembehelyezési szkripthez. A változók a következők:

    • CompletedBatches az üzembe helyezési szkript által használt ideiglenes tábla egyedi nevét tartalmazza annak nyomon követéséhez, hogy mely kötegek legyenek sikeresen befejezve a szkript végrehajtásakor
    • TotalBatchCount az üzembehelyezési szkriptben lévő kötegek teljes számát tartalmazza

    Egyéb típusok, tulajdonságok és érdekes módszerek a következők:

    StringBuilder, DeploymentScriptStepés AddBefore.

    Ezután definiálja a metódus által hívott segédmetódusokat.

A segítő metódusok hozzáadása

  • Több segédmetelyt kell definiálni. A fontos módszerek a következők:

    metódus leírás
    CreateExecuteSQL Határozza meg a CreateExecuteSQL metódust, amely egy megadott utasítást egy EXEC sp_executesql utasítással vesz körül. A kulcstípusok, metódusok és tulajdonságok a következő DacFx API-összetevőket tartalmazzák: ExecuteStatement, ExecuteableProcedureReference, SchemaObjectName, ProcedureReferenceés ExecuteParameter.
    CreateCompletedBatchesName Adja meg a CreateCompletedBatchesName metódust. Ez a metódus létrehozza a köteg ideiglenes táblájába beszúrt nevet. A kulcstípusok, metódusok és tulajdonságok a következő DacFx API-összetevőket tartalmazzák: SchemaObjectName.
    IsStatementEscaped Adja meg az IsStatementEscaped metódust. Ez a módszer meghatározza, hogy a modellelem típusa megköveteli-e az utasítás burkolását egy EXEC sp_executesql utasításba, mielőtt szerepelhetne egy IF utasításban. A kulcstípusok, metódusok és tulajdonságok a következő DacFx API-összetevőket tartalmazzák: TSqlObject.ObjectType, ModelTypeClass és TypeClass tulajdonság a következő modelltípusokhoz: Séma, Eljárás, Nézet, TableValuedFunction, ScalarFunction, DatabaseDdlTrigger, DmlTrigger, ServerDdlTrigger.
    TételkészítésTeljesBeszúrás Adja meg a CreateBatchCompleteInsert metódust. Ez a metódus létrehozza a központi telepítési szkripthez hozzáadott INSERT utasítást a szkript végrehajtásának előrehaladásának nyomon követéséhez. A kulcstípusok, metódusok és tulajdonságok a következő DacFx API-összetevőket tartalmazzák: InsertStatement, NamedTableReference, ColumnReferenceExpression, ValuesInsertSource és RowValue.
    CreateIfNotExecutedStatement Adja meg a CreateIfNotExecutedStatement metódust. Ez a metódus létrehoz egy IF utasítást, amely ellenőrzi, hogy az ideiglenes kötegek végrehajtották-e már a táblázat szerint, ami azt jelzi, hogy ez a köteg már végrehajtásra került. A kulcstípusok, metódusok és tulajdonságok a következők: IfStatement, ExistsPredicate, ScalarSubquery, NamedTableReference, WhereClause, ColumnReferenceExpression, IntegerLiteral, BooleanComparisonExpression és BooleanNotExpression.
    GetStepInfo Adja meg a GetStepInfo metódust. Ez a metódus a lépés szkriptjének létrehozásához használt modellelemre vonatkozó információkat nyer ki a lépésnév mellett. Az érdeklődési körök típusai és módszerei a következők: DeploymentPlanContributorContext, DeploymentScriptDomStep, TSqlObject, CreateElementStep, AlterElementStepés DropElementStep.
    GetElementName Formázott nevet hoz létre egy TSqlObjecthez.
  1. Adja hozzá a következő kódot a segítő metódusok definiálásához:

    
    /// <summary>  
    /// The CreateExecuteSql method "wraps" the provided statement script in an "sp_executesql" statement  
    /// Examples of statements that must be so wrapped include: stored procedures, views, and functions  
    /// </summary>  
    private static ExecuteStatement CreateExecuteSql(string statementScript)  
    {  
        // define a new Exec statement  
        ExecuteStatement executeSp = new ExecuteStatement();  
        ExecutableProcedureReference spExecute = new ExecutableProcedureReference();  
        executeSp.ExecuteSpecification = new ExecuteSpecification { ExecutableEntity = spExecute };  
    
        // define the name of the procedure that you want to execute, in this case sp_executesql  
        SchemaObjectName procName = new SchemaObjectName();  
        procName.Identifiers.Add(CreateIdentifier("sp_executesql", QuoteType.NotQuoted));  
        ProcedureReference procRef = new ProcedureReference { Name = procName };  
    
        spExecute.ProcedureReference = new ProcedureReferenceName { ProcedureReference = procRef };  
    
        // add the script parameter, constructed from the provided statement script  
        ExecuteParameter scriptParam = new ExecuteParameter();  
        spExecute.Parameters.Add(scriptParam);  
        scriptParam.ParameterValue = new StringLiteral { Value = statementScript };  
        scriptParam.Variable = new VariableReference { Name = "@stmt" };  
        return executeSp;  
    }  
    
    /// <summary>  
    /// The CreateIdentifier method returns a Identifier with the specified value and quoting type  
    /// </summary>  
    private static Identifier CreateIdentifier(string value, QuoteType quoteType)  
    {  
        return new Identifier { Value = value, QuoteType = quoteType };  
    }  
    
    /// <summary>  
    /// The CreateCompletedBatchesName method creates the name that will be inserted  
    /// into the temporary table for a batch.  
    /// </summary>  
    private static SchemaObjectName CreateCompletedBatchesName()  
    {  
        SchemaObjectName name = new SchemaObjectName();  
        name.Identifiers.Add(CreateIdentifier("tempdb", QuoteType.SquareBracket));  
        name.Identifiers.Add(CreateIdentifier("dbo", QuoteType.SquareBracket));  
        name.Identifiers.Add(CreateIdentifier(CompletedBatchesVariable, QuoteType.SquareBracket));  
        return name;  
    }  
    
    /// <summary>  
    /// Helper method that determines whether the specified statement needs to  
    /// be escaped  
    /// </summary>  
    /// <param name="sqlObject"></param>  
    /// <returns></returns>  
    private static bool IsStatementEscaped(TSqlObject sqlObject)  
    {  
        HashSet<ModelTypeClass> escapedTypes = new HashSet<ModelTypeClass>  
        {  
            Schema.TypeClass,  
            Procedure.TypeClass,  
            View.TypeClass,  
            TableValuedFunction.TypeClass,  
            ScalarFunction.TypeClass,  
            DatabaseDdlTrigger.TypeClass,  
            DmlTrigger.TypeClass,  
            ServerDdlTrigger.TypeClass  
        };  
        return escapedTypes.Contains(sqlObject.ObjectType);  
    }  
    
    /// <summary>  
    /// Helper method that creates an INSERT statement to track a batch being completed  
    /// </summary>  
    /// <param name="batchId"></param>  
    /// <param name="batchDescription"></param>  
    /// <returns></returns>  
    private static InsertStatement CreateBatchCompleteInsert(int batchId, string batchDescription)  
    {  
        InsertStatement insert = new InsertStatement();  
        NamedTableReference batchesCompleted = new NamedTableReference();  
        insert.InsertSpecification = new InsertSpecification();  
        insert.InsertSpecification.Target = batchesCompleted;  
        batchesCompleted.SchemaObject = CreateCompletedBatchesName();  
    
        // Build the columns inserted into  
        ColumnReferenceExpression batchIdColumn = new ColumnReferenceExpression();  
        batchIdColumn.MultiPartIdentifier = new MultiPartIdentifier();  
        batchIdColumn.MultiPartIdentifier.Identifiers.Add(CreateIdentifier(BatchIdColumnName, QuoteType.NotQuoted));  
    
        ColumnReferenceExpression descriptionColumn = new ColumnReferenceExpression();  
        descriptionColumn.MultiPartIdentifier = new MultiPartIdentifier();  
        descriptionColumn.MultiPartIdentifier.Identifiers.Add(CreateIdentifier(DescriptionColumnName, QuoteType.NotQuoted));  
    
        insert.InsertSpecification.Columns.Add(batchIdColumn);  
        insert.InsertSpecification.Columns.Add(descriptionColumn);  
    
        // Build the values inserted  
        ValuesInsertSource valueSource = new ValuesInsertSource();  
        insert.InsertSpecification.InsertSource = valueSource;  
    
        RowValue values = new RowValue();  
        values.ColumnValues.Add(new IntegerLiteral { Value = batchId.ToString() });  
        values.ColumnValues.Add(new StringLiteral { Value = batchDescription });  
        valueSource.RowValues.Add(values);  
    
        return insert;  
    }  
    
    /// <summary>  
    /// This is a helper method that generates an if statement that checks the batches executed  
    /// table to see if the current batch has been executed.  The if statement will look like this  
    ///   
    /// if not exists(select 1 from [tempdb].[dbo].[$(CompletedBatches)]   
    ///                where BatchId = batchId)  
    /// begin  
    /// end  
    /// </summary>  
    /// <param name="batchId"></param>  
    /// <returns></returns>  
    private static IfStatement CreateIfNotExecutedStatement(int batchId)  
    {  
        // Create the exists/select statement  
        ExistsPredicate existsExp = new ExistsPredicate();  
        ScalarSubquery subQuery = new ScalarSubquery();  
        existsExp.Subquery = subQuery;  
    
        subQuery.QueryExpression = new QuerySpecification  
        {  
            SelectElements =  
            {  
                new SelectScalarExpression  { Expression = new IntegerLiteral { Value ="1" } }  
            },  
            FromClause = new FromClause  
            {  
                TableReferences =  
                    {  
                        new NamedTableReference() { SchemaObject = CreateCompletedBatchesName() }  
                    }  
            },  
            WhereClause = new WhereClause  
            {  
                SearchCondition = new BooleanComparisonExpression  
                {  
                    ComparisonType = BooleanComparisonType.Equals,  
                    FirstExpression = new ColumnReferenceExpression  
                    {  
                        MultiPartIdentifier = new MultiPartIdentifier  
                        {  
                            Identifiers = { CreateIdentifier(BatchIdColumnName, QuoteType.SquareBracket) }  
                        }  
                    },  
                    SecondExpression = new IntegerLiteral { Value = batchId.ToString() }  
                }  
            }  
        };  
    
        // Put together the rest of the statement  
        IfStatement ifNotExists = new IfStatement  
        {  
            Predicate = new BooleanNotExpression  
            {  
                Expression = existsExp  
            }  
        };  
    
        return ifNotExists;  
    }  
    
    /// <summary>  
    /// Helper method that generates a useful description of the step.  
    /// </summary>  
    private static void GetStepInfo(  
        DeploymentScriptDomStep domStep,  
        out string stepDescription,  
        out TSqlObject element)  
    {  
        element = null;  
    
        // figure out what type of step we've got, and retrieve  
        // either the source or target element.  
        if (domStep is CreateElementStep)  
        {  
            element = ((CreateElementStep)domStep).SourceElement;  
        }  
        else if (domStep is AlterElementStep)  
        {  
            element = ((AlterElementStep)domStep).SourceElement;  
        }  
        else if (domStep is DropElementStep)  
        {  
            element = ((DropElementStep)domStep).TargetElement;  
        }  
    
        // construct the step description by concatenating the type and the fully qualified  
        // name of the associated element.  
        string stepTypeName = domStep.GetType().Name;  
        if (element != null)  
        {  
            string elementName = GetElementName(element);  
    
            stepDescription = string.Format(CultureInfo.InvariantCulture, "{0} {1}",  
                stepTypeName, elementName);  
        }  
        else  
        {  
            // if the step has no associated element, just use the step type as the description  
            stepDescription = stepTypeName;  
        }  
    }  
    
    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();  
    }  
    
    
  2. Mentse a módosításokat a SqlRestartableScriptContributor.cs.

A következő lépésben elkészíti az osztálykönyvtárat.

A szerelvény aláírása és összeszerelése

  1. A Project menüjében kattintson MyOtherDeploymentContributor Propertieselemre.

  2. Kattintson az Aláírás fülre.

  3. Kattintson A szerelvény aláírásagombra.

  4. A Válasszon egy erős névkulcsfájlt, kattintson <Új>gombra.

  5. Az Erős névkulcs létrehozása párbeszédpanel Kulcsfájl nevemezőbe írja be MyRefKey.

  6. (nem kötelező) Megadhat egy jelszót az erős névkulcsfájlhoz.

  7. Kattintson OKgombra.

  8. A Fájl menüben kattintson Az összes mentéseelemre.

  9. A Build menüben kattintson Megoldás létrehozásaelemre.

    Ezután telepítenie kell a szerelvényt, hogy az SQL-projektek üzembe helyezésekor be legyen töltve.

Üzembehelyezési közreműködő telepítése

Üzembe helyezési közreműködő telepítéséhez másolja a szerelvényt és a társított .pdb fájlt a Bővítmények mappába.

A MyOtherDeploymentContributor szerelvény telepítése

  1. Következő lépésként átmásolja az összeállítás adatait a Bővítmények könyvtárába. A Visual Studio 2022 indításakor azonosítja a %Program Fájlok%\Microsoft Visual Studio\2022\Enterprise\Common7\IDE\Extensions\Microsoft\SQLDB\DAC könyvtár és alkönyvtárak bővítményeit, és elérhetővé teszi őket használatra.

  2. Másolja a MyOtherDeploymentContributor.dll szerelvényfájlt a kimeneti könyvtárból a %Program Fájlok%\Microsoft Visual Studio\2022\Enterprise\Common7\IDE\Extensions\Microsoft\SQLDB\DAC könyvtárba. Alapértelmezés szerint a lefordított .dll fájl elérési útja a YourSolutionPath\YourProjectPath\bin\Debug vagy YourSolutionPath\YourProjectPath\bin\Release.

A telepítési eszköz futtatása vagy tesztelése

Az üzembehelyezési közreműködő futtatásához vagy teszteléséhez a következő feladatokat kell elvégeznie:

  • Adjon hozzá tulajdonságokat a létrehozni kívánt .sqlproj fájlhoz.

  • Telepítse az adatbázisprojektet az MSBuild használatával, és adja meg a megfelelő paramétereket.

Tulajdonságok hozzáadása az SQL Project (.sqlproj) fájlhoz

Mindig frissítenie kell az SQL-projektfájlt a futtatni kívánt közreműködők azonosítójának megadásához. Az SQL-projektet kétféleképpen frissítheti:

  1. A szükséges argumentumok hozzáadásához manuálisan módosíthatja az .sqlproj fájlt. Ezt akkor is megteheti, ha a közreműködő nem rendelkezik a konfigurációhoz szükséges közreműködői argumentumokkal, vagy ha nem kívánja újra felhasználni a build közreműködőt számos projektben. Ha ezt a lehetőséget választja, adja hozzá a következő utasításokat az .sqlproj fájlhoz a fájl első importálási csomópontja után:

    <PropertyGroup>  
      <DeploymentContributors>  
        $(DeploymentContributors); MyOtherDeploymentContributor.RestartableScriptContributor  
      </DeploymentContributors>  
    </PropertyGroup>  
    
  2. A második módszer egy célfájl létrehozása, amely tartalmazza a szükséges közreműködői argumentumokat. Ez akkor hasznos, ha ugyanazt a közreműködőt több projekthez használja, és közreműködői argumentumokat kell megadnia, mivel azok tartalmazzák az alapértelmezett értékeket. Ebben az esetben hozzon létre egy célfájlt az MSBuild bővítmények elérési útján:

    1. Navigáljon a %Program Fájlok%\MSBuild mappába.

    2. Hozzon létre egy új mappát a "MyContributors" mappában, ahol a célfájlokat tárolja.

    3. Hozzon létre egy új "MyContributors.targets" fájlt ebben a könyvtárban, adja hozzá a következő szöveget, és mentse a fájlt:

      <?xml version="1.0" encoding="utf-8"?>  
      
      <Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">  
        <PropertyGroup>  
          <DeploymentContributors>$(DeploymentContributors);MyOtherDeploymentContributor.RestartableScriptContributor</DeploymentContributors>  
        </PropertyGroup>  
      </Project>  
      
      
    4. A .sqlproj fájlban, amely projekt esetében közreműködőket szeretne futtatni, importálja a targets fájlt azáltal, hogy hozzáadja a következő utasítást az .sqlproj fájlhoz a fájl <Import Project="$(MSBuildExtensionsPath)\Microsoft\VisualStudio\v$(VisualStudioVersion)\SSDT\Microsoft.Data.Tools.Schema.SqlTasks.targets" /> csomópontja után:

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

Miután követte az alábbi módszerek egyikét, az MSBuild használatával átadhatja a parancssori buildek paramétereit.

Jegyzet

A közreműködői azonosító megadásához mindig frissítenie kell a "DeploymentContributors" tulajdonságot. Ez ugyanaz az azonosító, amelyet a forrásfájl „ExportDeploymentPlanModifier” attribútumában használnak. Enélkül a támogatás nem fog futni a projekt építésekor. A "ContributorArguments" tulajdonságot csak akkor kell frissíteni, ha a közreműködő futtatásához szükséges argumentumok állnak rendelkezésre.

Az adatbázisprojekt üzembe helyezése

Az SQL-projekt üzembe helyezése és üzembe helyezési jelentés létrehozása

  • A projekt a Visual Studióban normál módon közzétehető vagy üzembe helyezhető. Egyszerűen nyisson meg egy sql-projektet tartalmazó megoldást, és válassza a Közzététel... lehetőséget a projekt helyi menüjében, vagy használja az F5-öt hibakeresési üzembe helyezéshez a LocalDB-be. Ebben a példában a "Közzététel..." párbeszédpanelen létrehozhat egy üzembehelyezési szkriptet.

    1. Nyissa meg a Visual Studiót, és nyissa meg az SQL Projectet tartalmazó megoldást.

    2. Kattintson a jobb gombbal a projektre a Megoldáskezelőben, és válassza a Közzététel... lehetőséget.

    3. Állítsa be a kiszolgáló nevét és az adatbázis nevét a közzétételhez.

    4. Válassza Szkript létrehozása lehetőséget a párbeszédpanel alján található beállítások közül. Ez a művelet létrehoz egy szkriptet, amely az üzembe helyezéshez használható. Megvizsgálhatjuk ezt a szkriptet annak ellenőrzéséhez, hogy az IF-utasítások hozzáadásra kerültek-e annak érdekében, hogy a szkript újraindítható legyen.

    5. Vizsgálja meg az eredményként kapott üzembehelyezési szkriptet. Az "Üzembe helyezés előtti szkriptsablon" feliratú szakasz előtt az alábbi Transact-SQL szintaxishoz hasonlót kell látnia:

      :setvar CompletedBatches __completedBatches_CompareProjectDB_cd1e348a-8f92-44e0-9a96-d25d65900fca  
      :setvar TotalBatchCount 17  
      GO  
      
      if OBJECT_ID(N'tempdb.dbo.$(CompletedBatches)', N'U') is null  
      begin  
      use tempdb  
      create table [dbo].[$(CompletedBatches)]  
      (  
      BatchId int primary key,  
      Description nvarchar(300)  
      )  
      use [$(DatabaseName)]  
      end  
      
      

      Az üzembehelyezési szkript későbbi részében minden köteg körül megjelenik egy IF utasítás, amely körülveszi az eredeti utasítást. A CREATE SCHEMA utasításhoz például a következő T-SQL-szkript jelenhet meg:

      IF NOT EXISTS (SELECT 1  
                     FROM   [tempdb].[dbo].[$(CompletedBatches)]  
                     WHERE  [BatchId] = 0)  
          BEGIN  
              EXECUTE sp_executesql @stmt = N'CREATE SCHEMA [Sales]  
          AUTHORIZATION [dbo]';  
              SET NOCOUNT ON;  
              INSERT  [tempdb].[dbo].[$(CompletedBatches)] (BatchId, Description)  
              VALUES                                      (0, N'CreateElementStep Sales batch 0');  
              SET NOCOUNT OFF;  
          END  
      
      

      Figyelje meg, hogy a CREATE SCHEMA azon utasítások egyike, amelyeket az IF utasításban szereplő EXECUTE sp_executesql utasításba kell beágyazni. Az olyan utasítások, mint a CREATE TABLE, nem igénylik az EXECUTE sp_executesql utasítást, és az alábbi példához hasonlóak:

      IF NOT EXISTS (SELECT 1  
                     FROM   [tempdb].[dbo].[$(CompletedBatches)]  
                     WHERE  [BatchId] = 1)  
          BEGIN  
              CREATE TABLE [Sales].[Customer] (  
                  [CustomerID]   INT           IDENTITY (1, 1) NOT NULL,  
                  [CustomerName] NVARCHAR (40) NOT NULL,  
                  [YTDOrders]    INT           NOT NULL,  
                  [YTDSales]     INT           NOT NULL  
              );  
              SET NOCOUNT ON;  
              INSERT  [tempdb].[dbo].[$(CompletedBatches)] (BatchId, Description)  
              VALUES                                      (1, N'CreateElementStep Sales.Customer batch 0');  
              SET NOCOUNT OFF;  
          END  
      
      

      Jegyzet

      Ha olyan adatbázisprojektet helyez üzembe, amely megegyezik a céladatbázissal, az eredményül kapott jelentés nem lesz túl értelmes. A hasznosabb eredmények érdekében helyezzen üzembe módosításokat egy adatbázisban, vagy helyezzen üzembe egy új adatbázist.

Parancssori üzembe helyezés generált dacpac-fájl használatával

Az SQL-projekt buildjének kimeneti összetevője egy dacpac-fájl. A dacpac-fájlokkal telepítheti a sémát a parancssorból, és amely lehetővé teszi az üzembe helyezést egy másik gépről, például egy buildelési gépről. Az SqlPackage egy parancssori segédprogram, amely számos lehetőséggel rendelkezik, amelyek lehetővé teszik a felhasználók számára a dacpac üzembe helyezését vagy üzembehelyezési szkriptek létrehozásának lehetőségét, többek között. További információ: SqlPackage.exe.

Jegyzet

A projektekből létrehozott, a DeploymentContributors tulajdonsággal definiált dacpacsok sikeres üzembe helyezéséhez telepíteni kell az üzembehelyezési közreműködő(k)t tartalmazó DLL-eket a használt gépen. Ennek az az oka, hogy az üzembe helyezés sikeres befejezéséhez szükségesként lettek megjelölve.

A követelmény elkerülése érdekében zárja ki az üzembehelyezési közreműködőt az .sqlproj fájlból. Ehelyett adja meg az üzembe helyezés során futtatandó közreműködőket az SqlPackage használatával az AdditionalDeploymentContributors paraméterrel. Ez olyan esetekben hasznos, amikor csak különleges körülmények között szeretne közreműködőt használni, például egy adott kiszolgálón való üzembe helyezést.

Következő lépések

A végrehajtás előtt kísérletezhet más típusú módosításokkal az üzembehelyezési terveken. Néhány egyéb módosítási típus, amelyet érdemes lehet elvégezni:

  • Bővített tulajdonság hozzáadása az összes olyan adatbázis-objektumhoz, amely verziószámot társít hozzájuk.

  • További diagnosztikai nyomtatási utasítások vagy megjegyzések hozzáadása vagy eltávolítása az üzembehelyezési szkriptekből.

Lásd még:

Adatbázis-létrehozás és -üzembe helyezés testreszabása összeállítási és üzembe helyezési közreműködők használatával
Útmutató: Az adatbázisprojekt felépítésének kiterjesztése a modellstatisztikák létrehozásához
útmutató: Az adatbázisprojekt üzembe helyezésének kiterjesztése az üzembehelyezési terv elemzéséhez