6

Quando si pubblica un dacpac con sqlpackage.exe, viene eseguito prima il confronto dello schema, seguito dagli script di pre-distribuzione. Ciò causa un problema quando, ad esempio, è necessario rilasciare una tabella o rinominare una colonna. Il confronto degli schemi è stato fatto prima che l'oggetto fosse modificato e la distribuzione fallisse. La pubblicazione deve essere ripetuta per tenere conto del nuovo schema.Schema confronto eseguito prima degli script di pre-distribuzione durante la pubblicazione

Chiunque ha una soluzione per questo che non prevede la pubblicazione due volte?

+0

I nomi devono essere gestiti in modo nativo se si utilizza la funzione Refactor. Anche le tabelle che cadono sono supportate nel progetto. Tuttavia, il suggerimento di Ed è valido per le volte in cui la funzionalità nativa non funzionerà. Che cosa stai cercando di eliminare/rinominare/eseguire ciò che deve essere fatto prima della comparazione dello schema? –

+0

In questo caso particolare, sto facendo cadere una chiave esterna modificando la colonna FK da BIGINT a INT e puntando l'FK su una tabella diversa che viene a sua volta rielaborata. La distribuzione fallisce la prima esecuzione perché il confronto degli schemi viene eseguito prima di queste modifiche. Si schiera alla seconda manche. – Metaphor

risposta

4

Gert Drapers chiamato come pre -pre-deployment script here

In realtà è una sfida. Se è necessario aggiungere una colonna chiave non nullable e straniera a una tabella piena di dati, è possibile farlo solo con uno script separato.

Se sei l'unico sviluppatore, non è un problema, ma quando hai una squadra numerosa che "script separato" deve essere in qualche modo eseguito prima di ogni pubblicazione DB.

La soluzione che abbiamo usato:

  • Creare SQL separato "Prima-pubblicare" lo script (in progetto DB), che ha una proprietà [Crea azione = Nessuno]
  • Crea custom MSBuild Task dove chiamare sqlcmd.exe utilità che passa lo script "Prima di pubblicare" come parametro e quindi per richiamare l'utilità SQLPACKAGE.EXE che passa DB.dacpac
  • Aggiungere una chiamata dell'attività personalizzata MSBuild al file db.sqlproj. Per esempio:
<UsingTask 
     TaskName="MSBuild.MsSql.DeployTask" 
     AssemblyFile="$(MSBuildProjectDirectory)\Deploy\MsBuild.MsSql.DeployTask.dll" /> 

<Target Name="AfterBuild"> 
    <DeployTask 
     Configuration="$(Configuration)" 
     DeployConfigPath="$(MSBuildProjectDirectory)\Deploy\Deploy.config" 
     ProjectDirectory="$(MSBuildProjectDirectory)" 
     OutputDirectory="$(OutputPath)" 
     DacVersion="$(DacVersion)"> 
    </DeployTask> 
</Target> 

MsBuild.MsSql.DeployTask.dll sopra è che personalizzato MSBuild Task.

Così lo script "Prima di pubblicare" potrebbe essere chiamato da Visual Studio.

Per CI è stato utilizzato un file batch (* .bat) in cui sono state richiamate le stesse due utilità (SQLCMD.EXE & SQLPACKAGE.EXE).

Il processo finale che abbiamo è un po 'complicato e dovrebbe essere descritto in un articolo separato - qui ho parlato di un solo senso :)

1

Abbiamo affrontato una situazione in cui abbiamo bisogno di trasformare i dati da una tabella in altri durante la distribuzione del progetto di database. Ovviamente è un problema utilizzare il progetto DB a causa della pre-distribuzione che la tabella di destinazione (colonna) non esiste ancora, ma nello script post-distribuzione la tabella di origine (colonna) è già assente.

per trasformare i dati da Tabella A a TableB abbiamo usato la seguente idea (Questo approccio può essere utilizzato per qualsiasi modifica dei dati):

  1. Developer aggiunge tabella di destinazione (dbo.TabellaB) nel progetto DB e distribuirlo sul DB locale (senza impegnarsi in un SVN)
  2. Lui o lei crea uno script di trasformazione pre-distribuzione. Il trucco è che lo script inserisce i dati dei risultati in una tabella temporanea: #TabellaB
  3. Lo sviluppatore elimina il dbo.TableA nel progetto DB. Si presume che la tabella verrà eliminata durante l'esecuzione dello script generato principale.
  4. Lo sviluppatore scrive uno script post-distribuzione che copia il modulo dati #TableB in dbo.TableB appena creato dallo script principale.
  5. Tutte le modifiche vengono confermate in SVN.

In questo modo non è necessario lo script di pre-distribuzione perché archiviamo i dati intermedi nella tabella temporanea.

Vorrei dire che l'approccio che utilizza lo script di pre-distribuzione ha gli stessi dati intermedi (temporanei), tuttavia è archiviato non in tabelle temporanee ma in tabelle reali. Accade tra pre-pre-distribuzione e pre-distribuzione. Dopo l'esecuzione dello script di pre-distribuzione, questi dati intermedi scompaiono.

Per di più, l'approccio con l'utilizzo di tabelle temporanee ci permette di affrontare la seguente situazione complicata ma reale: Immaginiamo che abbiamo due trasformazioni nel nostro progetto DB:

  1. TableA -> TableB
  2. TableB -> TableC

a parte che abbiamo due banche dati:

  1. DatabaeA che hanno il TableA
  2. DatabaeB in cui il TableA è già stato trasformato in TableB. Il TableA è assente nel DatabaseB.

Tuttavia possiamo affrontare questa situazione. Abbiamo bisogno solo di una nuova azione nella pre-distribuzione. Prima della trasformazione, proviamo a copiare i dati dal dbo.TableA in #TableA. E lo script di trasformazione funziona solo con tabelle temporanee.

Lascia che ti mostri come funziona questa idea in DatabaseA e DatabaseB. Si presume che il progetto DB abbia due coppie di script pre e post distribuzione: "TabellaA -> TabellaB" e "TabellaB -> TabellaC".

Di seguito è riportato l'esempio degli script per la trasformazione "TabellaB -> TabellaC".

pre-distribuzione di script script di

----[The data preparation block]--- 
--We must prepare to possible transformation 
--The condition should verufy the existance of necessary columns 
IF OBJECT_ID('dbo.TableB') IS NOT NULL AND 
    OBJECT_ID('tempdb..#TableB') IS NULL 
BEGIN 
    CREATE TABLE #TableB 
    (
     [Id] INT NOT NULL PRIMARY KEY, 
     [Value1] VARCHAR(50) NULL, 
     [Value2] VARCHAR(50) NULL 
    ) 

    INSERT INTO [#TableB] 
    SELECT [Id], [Value1], [Value2] 
    FROM dbo.TableB 
END 

----[The data transformation block]--- 
--The condition of the transformation start 
--It is very important. It must be as strict as posible to ward off wrong executions. 
--The condition should verufy the existance of necessary columns 
--Note that the condition and the transformation must use the #TableA instead of dbo.TableA 
IF OBJECT_ID('tempdb..#TableB') IS NOT NULL 
BEGIN 

    CREATE TABLE [#TableC] 
    (
     [Id] INT NOT NULL PRIMARY KEY, 
     [Value] VARCHAR(50) NULL 
    ) 

    --Data transformation. The source and destimation tables must be temporary tables. 
    INSERT INTO [#TableC] 
    SELECT [Id], Value1 + ' '+ Value2 as Value 
    FROM [#TableB] 

END 

post-distribuzione

Nel DatabaseA lo script di pre-distribuzione ha già creato il #TableA. Pertanto il blocco di preparazione dei dati non verrà eseguito a causa della mancanza di dbo.TableB nel database. Tuttavia la trasformazione dei dati verrà eseguita perché c'è il #TableA nel database che è stato creato dal blocco di trasformazione di "TableA -> TableB".

Nel DatabaseB i blocchi di preparazione e trasformazione dei dati per lo script "TabellaA -> TabellaB" non verranno eseguiti. Tuttavia abbiamo già i dati trasformati nel dbo.TableB. Quindi i blocchi di preparazione e trasformazione dei dati per "TableB -> TableC" verranno eseguiti senza alcun problema.

Problemi correlati