Anteckning
Åtkomst till den här sidan kräver auktorisering. Du kan prova att logga in eller ändra kataloger.
Åtkomst till den här sidan kräver auktorisering. Du kan prova att ändra kataloger.
Du kan skapa distributionsdeltagare för att utföra anpassade åtgärder när du distribuerar ett SQL-projekt. Du kan skapa antingen en DeploymentPlanModifier- eller en DeploymentPlanExecutor-. Använd en DeploymentPlanModifier för att ändra planen innan den körs och en DeploymentPlanExecutor för att utföra åtgärder medan planen körs. I den här genomgången skapar du en DeploymentPlanModifier med namnet SqlRestartableScriptContributor. DeploymentPlanModifier SqlRestartableScriptContributor lägger IF till instruktioner till batcharna i distributionsskriptet så att skriptet kan köras igen tills de har slutförts om ett fel inträffar under körningen.
I den här genomgången utför du följande viktiga uppgifter:
- Skapa DistributionPlanModifier-typen av distributionsdeltagare
- Installera distributionskomponenten
- Kör eller testa din distributionsbidragsgivare
Förutsättningar
Du behöver följande komponenter för att slutföra den här genomgången:
Du måste ha installerat en version av Visual Studio som innehåller SQL Server Data Tools och stöder C#-utveckling.
Du måste ha ett SQL-projekt som innehåller SQL-objekt.
En instans av SQL Server som du kan distribuera ett databasprojekt till.
Not
Den här genomgången är avsedd för användare som redan är bekanta med SQL-funktionerna i SQL Server Data Tools. Du förväntas också känna till grundläggande Visual Studio-begrepp, till exempel hur du skapar ett klassbibliotek och hur du använder kodredigeraren för att lägga till kod i en klass.
Skapa en distributionsdeltagare
Om du vill skapa en distributionsdeltagare måste du utföra följande uppgifter:
- Skapa ett klassbiblioteksprojekt och lägg till nödvändiga referenser.
- Definiera en klass med namnet SqlRestartableScriptContributor som ärver från DeploymentPlanModifier.
- Åsidosätt metoden OnExecute.
- Lägg till privata hjälpmetoder.
- Skapa den resulterande sammansättningen.
Skapa ett klassbiblioteksprojekt
- Skapa ett C#-klassbiblioteksprojekt (.NET Framework) med namnet MyOtherDeploymentContributor.
- Byt namn på filen "Class1.cs" till "SqlRestartableScriptContributor.cs".
- Högerklicka på projektnoden i Solution Explorer och välj sedan Lägg till referens.
- Välj System.ComponentModel.Composition på fliken Ramverk.
- På menyn Project väljer du alternativet Hantera NuGet-paket. Installera de senaste stabila versionerna för Microsoft.SqlServer.DacFx.
Börja sedan lägga till kod i klassen.
Definiera klassen SqlRestartableScriptContributor
Uppdatera filen class1.cs i kodredigeraren så att den matchar följande med hjälp av-instruktioner:
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;Uppdatera klassdefinitionen så att den matchar följande exempel:
/// <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 { }Nu har du definierat din distributionsdeltagare som ärver från DeploymentPlanModifier. Under bygg- och distributionsprocessen läses anpassade komponenter in från en standardtilläggskatalog. De bidragsgivare som ändrar distributionsplanen identifieras med attributet ExportDeploymentPlanModifier. Det här attributet krävs för att deltagare ska kunna identifieras. Det här attributet bör se ut ungefär som följande funktionsdekoratör:
[ExportDeploymentPlanModifier("MyOtherDeploymentContributor.RestartableScriptContributor", "1.0.0.0")]Lägg till följande medlemsdeklarationer:
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 ";Därefter åsidosätter du metoden OnExecute för att lägga till den kod som du vill köra när ett databasprojekt distribueras.
Åsidosätt OnExecute
Lägg till följande metod i klassen SqlRestartableScriptContributor:
/// <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 }Du åsidosätter metoden OnExecute från basklassen DeploymentPlanContributor. DeploymentPlanContributor är basklassen för både DeploymentPlanModifier och DeploymentPlanExecutor. Ett DeploymentPlanContributorContext--objekt skickas till metoden OnExecute, vilket ger åtkomst till angivna argument, målkällan och databasmodellen, distributionsplanen och distributionsalternativen. I det här exemplet får vi distributionsplanen och måldatabasnamnet.
Lägg nu till början av en brödtext i metoden OnExecute:
// 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);I den här koden definierar vi några lokala variabler och konfigurerar loopen som hanterar bearbetning av alla steg i distributionsplanen. När loopen har slutförts måste vi utföra viss efterbearbetning och sedan ta bort den tillfälliga tabell som vi skapade under utplaceringen för att spåra förloppet när planen utfördes. Här är följande nyckeltyper: DeploymentStep och DeploymentScriptStep. En nyckelmetod är AddAfter.
Lägg nu till ytterligare stegbearbetning för att ersätta kommentaren med texten "Lägg till ytterligare stegbearbetning här":
// Look for steps that mark the pre/post deployment scripts // These steps are always 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 are enclosed in an if statement that checks // 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 }Kodkommentarna förklarar bearbetningen. På hög nivå letar den här koden efter de steg som du bryr dig om, hoppar över andra och stoppar när du kommer till början av stegen efter distributionen. Om steget innehåller instruktioner som vi måste omge med villkor utför vi extra bearbetning. Nyckeltyper, metoder och egenskaper innehåller följande komponenter från DacFx-biblioteket: BeginPreDeploymentScriptStep, BeginPostDeploymentScriptStep, TSqlObject, TSqlScript, Script, DeploymentScriptDomStepoch SqlPrintStep.
Lägg nu till batchbearbetningskoden genom att ersätta kommentaren med texten "Lägg till batchbearbetning här":
// Create the if statement that contains 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++;Den här koden skapar en
IF-instruktion tillsammans med ettBEGIN/ENDblock. Sedan utför vi extra bearbetning på -uttrycken i batchen. När det är klart lägger vi till enINSERTinstruktion för att lägga till information i den tillfälliga tabellen som spårar förloppet för skriptkörningen. Slutligen uppdaterar du batchen och ersätter de instruktioner som tidigare fanns där med den nyaIFsom innehåller dessa instruktioner i den. Viktiga typer, metoder och egenskaper är: IfStatement, BeginEndBlockStatement, StatementList, TSqlBatch, PredicateSetStatement, SetOptions och InsertStatement.Lägg nu till brödtexten i instruktionsbearbetningsloopen. Ersätt kommentaren med texten "Lägg till ytterligare satsbearbetning här":
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);För varje instruktion i batchen, om instruktionen är av en typ som måste omslutas med en
sp_executesql-instruktion, ändra instruktionen i enlighet med detta. Koden lägger sedan till -instruktionen i instruktionslistan för blocketBEGIN/ENDsom du skapade. Nyckeltyper, metoder och egenskaper omfattar TSqlStatement och ExecuteStatement.Lägg slutligen till efterbearbetningsavsnittet i stället för kommentaren med texten "Lägg till ytterligare efterbearbetning här":
// Declare a SqlCmd variables. // // CompletedBatches variable - defines the name of the table in tempdb that tracks 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 use to track the work that we are doing DeploymentScriptStep createStatusTableStep = new DeploymentScriptStep(CreateCompletedBatchesTable); base.AddBefore(context.PlanHandle, beforePreDeploy, createStatusTableStep);Om vår bearbetning hittade ett eller flera steg som vi omgav med en villkorsstyrd instruktion måste vi lägga till instruktioner i distributionsskriptet för att definiera SQLCMD-variabler. Variablerna är:
CompletedBatchesinnehåller ett unikt namn för den temporära tabell som distributionsskriptet använder för att hålla reda på vilka batchar som har slutförts när skriptet körsTotalBatchCountinnehåller det totala antalet batchar i distributionsskriptet
Andra typer, egenskaper och intressanta metoder är:
StringBuilder, DeploymentScriptStep ochAddBefore.Därefter definierar du de hjälpmetoder som anropas med den här metoden.
Lägg till hjälpmetoderna
Flera hjälpmetoder måste definieras. Viktiga metoder är:
Metod Description CreateExecuteSQLDefiniera metoden CreateExecuteSQL för att omge en angiven instruktion med en EXECsp_executesql-instruktion. Nyckeltyper, metoder och egenskaper omfattar följande DacFx API-komponenter: ExecuteStatement, ExecutableProcedureReference, SchemaObjectName, ProcedureReferenceoch ExecuteParameter.CreateCompletedBatchesNameDefiniera metoden CreateCompletedBatchesName. Den här metoden skapar namnet som infogas i den temporära tabellen för en batch. Viktiga typer, metoder och egenskaper omfattar följande DacFx API-komponenter: SchemaObjectName. IsStatementEscapedDefiniera metoden IsStatementEscaped. Den här metoden avgör om typen av modellelement kräver att -instruktionen omsluts i en EXECsp_executesql-instruktion innan den kan omges av enIF-instruktion. Nyckeltyper, metoder och egenskaper omfattar följande DacFx API-komponenter: TSqlObject.ObjectType, ModelTypeClass och egenskapen TypeClass för följande modelltyper: Schema, Procedure, View, TableValuedFunction, ScalarFunction, DatabaseDdlTrigger, DmlTrigger, ServerDdlTrigger.CreateBatchCompleteInsertDefiniera metoden CreateBatchCompleteInsert. Den här metoden skapar instruktionen INSERTsom läggs till i distributionsskriptet för att spåra förloppet för skriptkörning. Nyckeltyper, metoder och egenskaper omfattar följande DacFx API-komponenter: InsertStatement, NamedTableReference, ColumnReferenceExpression, ValuesInsertSource och RowValue.CreateIfNotExecutedStatementDefiniera metoden CreateIfNotExecutedStatement. Den här metoden genererar en IFinstruktion som kontrollerar om den tillfälliga batchkörningstabellen anger att den här batchen redan har körts. Viktiga typer, metoder och egenskaper är: IfStatement, ExistsPredicate, ScalarSubquery, NamedTableReference, WhereClause, ColumnReferenceExpression, IntegerLiteral, BooleanComparisonExpression och BooleanNotExpression.GetStepInfoDefiniera metoden GetStepInfo. Den här metoden extraherar information om modellelementet som används för att skapa stegets skript, utöver stegnamnet. Typer och metoder av intresse är: DeploymentPlanContributorContext, DeploymentScriptDomStep, TSqlObject, CreateElementStep, AlterElementStep och DropElementStep. GetElementNameSkapar ett formaterat namn för en TSqlObject.
Lägg till följande kod för att definiera hjälpmetoderna:
/// <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 is 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 looks 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(); }Spara ändringarna i SqlRestartableScriptContributor.cs.
Sedan skapar du klassbiblioteket.
Signera och skapa sammansättningen
På projektmenyn väljer du Egenskaper för MyOtherDeploymentContributor.
Välj fliken Signering .
Välj Signera sammansättningen.
I Välj en nyckelfil med starkt namn väljer du <Nytt>.
I dialogrutan Skapa stark namnnyckel skriver du MyRefKeyi Nyckelfilnamn.
(valfritt) Du kan ange ett lösenord för din starka namnnyckelfil.
Välj OK.
På menyn Arkiv väljer du Spara alla.
På menyn Build väljer du Build Solution.
Därefter måste du installera assemblyn så att den laddas in när du distribuerar SQL-projekt.
Installera en distributionsbidragare
Om du vill installera en distributionsdeltagare måste du kopiera sammansättningen och den associerade .pdb filen till mappen Tillägg.
Installera sammansättningen MyOtherDeploymentContributor
Därefter kopierar du sammansättningsinformationen till katalogen Tillägg. När Visual Studio 2022 startar identifierar det eventuella tillägg i
%ProgramFiles%\Microsoft Visual Studio\2022\Enterprise\Common7\IDE\Extensions\Microsoft\SQLDB\DACkatalogen och underkatalogerna och gör dem tillgängliga för användning.Kopiera sammansättningsfilen MyOtherDeploymentContributor.dll från utdatakatalogen till
%ProgramFiles%\Microsoft Visual Studio\2022\Enterprise\Common7\IDE\Extensions\Microsoft\SQLDB\DAC-katalogen. Som standardinställning är sökvägen till din kompilerade.dllfilYourSolutionPath\YourProjectPath\bin\DebugellerYourSolutionPath\YourProjectPath\bin\Release.
Köra eller testa distributionsdeltagaren
Om du vill köra eller testa distributionsdeltagaren måste du utföra följande uppgifter:
Lägg till egenskaper i filen
.sqlprojsom du planerar att skapa.Distribuera databasprojektet med hjälp av MSBuild och ange lämpliga parametrar.
Lägga till egenskaper i SQL-projektfilen (.sqlproj)
Du måste alltid uppdatera SQL-projektfilen för att ange ID för de deltagare som du vill köra. Du kan uppdatera SQL-projektet på något av två sätt:
Du kan ändra
.sqlprojfilen manuellt för att lägga till de argument som krävs. Du kan välja att göra detta om din deltagare inte har några deltagarargument som krävs för konfigurationen, eller om du inte tänker återanvända byggdeltagaren i ett stort antal projekt. Om du väljer det här alternativet lägger du till följande instruktioner i.sqlprojfilen efter den första importnoden i filen:<PropertyGroup> <DeploymentContributors> $(DeploymentContributors); MyOtherDeploymentContributor.RestartableScriptContributor </DeploymentContributors> </PropertyGroup>Den andra metoden är att skapa en målfil som innehåller de obligatoriska deltagarargumenten. Detta är användbart om du använder samma deltagare för flera projekt och har deltagarargument som krävs, eftersom det innehåller standardvärdena. I det här fallet skapar du en målfil i sökvägen för MSBuild-tillägg:
Gå till
%ProgramFiles%\MSBuild.Skapa en ny mapp "MyContributors" där dina målfiler lagras.
Skapa en ny fil "MyContributors.targets" i den här katalogen, lägg till följande text i den och spara filen:
<?xml version="1.0" encoding="utf-8"?> <Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> <PropertyGroup> <DeploymentContributors>$(DeploymentContributors);MyOtherDeploymentContributor.RestartableScriptContributor</DeploymentContributors> </PropertyGroup> </Project>.sqlprojI filen för alla projekt som du vill köra deltagare importerar du målfilen genom att lägga till följande instruktion i.sqlprojfilen efter <Import Project="$(MSBuildExtensionsPath)\Microsoft\VisualStudio\v$(VisualStudioVersion)\SSDT\Microsoft.Data.Tools.Schema.SqlTasks.targets" />node i filen:<Import Project="$(MSBuildExtensionsPath)\MyContributors\MyContributors.targets " />
När du har följt någon av dessa metoder kan du använda MSBuild för att skicka in parametrarna för kommandoradsversioner.
Not
Du måste alltid uppdatera egenskapen "DeploymentContributors" för att ange ditt deltagar-ID. Det här är samma ID som används i attributet "ExportDeploymentPlanModifier" i din källfil för bidragsgivare. Utan detta körs inte komponenten när du bygger projektet. Egenskapen "ContributorArguments" behöver bara uppdateras om du har argument som krävs för att din medverkande ska kunna köra.
Distribuera databasprojektet
Projektet kan publiceras eller distribueras som vanligt i Visual Studio. Öppna en lösning som innehåller ditt SQL-projekt och välj Publicera... från snabbmenyn för projektet eller använd F5 för en felsökningsdistribution till LocalDB. I det här exemplet använder vi "Publicera..." dialogruta för att generera ett distributionsskript.
Öppna Visual Studio och öppna lösningen som innehåller ditt SQL-projekt.
Högerklicka på projektet i Solution Explorer och välj alternativet Publicera....
Ange servernamnet och databasnamnet som ska publiceras till.
Välj Generera skript från alternativen längst ned i dialogrutan. Den här åtgärden skapar ett skript som kan användas för distribution. Vi kan undersöka det här skriptet för att verifiera att våra
IFinstruktioner har lagts till för att göra skriptet omstartsbart.Granska det resulterande distributionsskriptet. Precis innan avsnittet med etiketten "Skriptmall före distribution" bör du se något som liknar följande Transact-SQL syntax:
: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)]; ENDSenare i distributionsskriptet, runt varje batch, ser du en
IFinstruktion som omger den ursprungliga instruktionen. Följande T-SQL-skript kan till exempel visas för enCREATE SCHEMAinstruktion: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; ENDCREATE SCHEMAär en av de instruktionerna som måste vara inneslutna i enEXECUTEsp_executesql-instruktion inomIF-instruktionen. Instruktioner somCREATE TABLEkräver inte instruktionenEXECUTEsp_executesqloch liknar följande exempel: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; ENDNot
Om du distribuerar ett databasprojekt som är identiskt med måldatabasen är den resulterande rapporten inte särskilt meningsfull. Om du vill ha mer meningsfulla resultat kan du antingen distribuera ändringar till en databas eller distribuera en ny databas.
Kommandoradsdistribution med genererad dacpac-fil
Utdataartefakten från en SQL-projektversion är en .dacpac fil. En .dacpac fil kan användas för att distribuera schemat från kommandoraden och som kan aktivera distribution från en annan dator, till exempel en byggdator. SqlPackage är ett kommandoradsverktyg med ett komplett utbud av alternativ som gör det möjligt för användare att distribuera ett dacpac eller generera ett distributionsskript, bland andra åtgärder. Mer information finns i SqlPackage.
Not
Om du vill distribuera dacpacs som skapats från projekt med egenskapen DeploymentContributors definierad måste DLL:er som innehåller dina distributionsdeltagare installeras på den dator som används. Det beror på att de har markerats som nödvändiga för att distributionen ska slutföras.
Undvik det här kravet genom att exkludera distributionsdeltagaren .sqlproj från filen. Istället, ange deltagare som ska köras under distributionen med hjälp av SqlPackage med parametern AdditionalDeploymentContributors. Detta är användbart i fall där du bara vill använda en bidragsgivare för speciella fall, som att distribuera till en specifik server.