Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

DACPAC schema compare runs before pre-deployment scripts during publish

When publishing a dacpac with sqlpackage.exe, it runs Schema Compare first, followed by pre-deployment scripts. This causes a problem when, for instance, you need to drop a table or rename a column. Schema Compare was done before the object was modified and the deployment fails. Publish must be repeated to take the new schema into account.

Anyone have a work-around for this that does not involve publishing twice?

like image 368
Metaphor Avatar asked Sep 01 '15 11:09

Metaphor


People also ask

What is pre-deployment script in database project?

A pre-deployment script can copy data from a table that is being changed into a temporary table before re-formatting and applying the data to the changed table in a post-deployment script, You can insert reference data that must exist in a table in a post-deployment script.

Can you use a Dacpac publish profile to deploy to production?

Once you have a DACPAC, it can be deployed using the Publish function in Visual Studio, or by using the SqlPackage.exe command-line interface. The Publish DACPAC task simplifies the use of SqlPackage.exe to deploy a database from a DACPAC using a DAC Publish Profile.

How do I publish a Dacpac database?

A simple command would be "sqlpackage /a:publish /sf:db1. dacpac /tsn:localhost /tdn:db1" to publish dacpac "db1" to a database "localhost\db1". For other publish options type "sqlpackage /a:publish /?" to get the list of applicable actions on the command line.


2 Answers

Gert Drapers called it as pre-pre-deployment script here

Actually it is a challenge. If you need to add non-nullable and foreign key column to a table full of data - you can do with a separate script only.

If you are the only developer - that is not a problem, but when you have a large team that "separate script" has to be somehow executed before every DB publish.

The workaround we used:

  • Create separate SQL "Before-publish" script (in DB project) which has a property [Build action = None]
  • Create custom MSBuild Task where to call SQLCMD.EXE utility passing "Before-publish" script as a parameter, and then to call SQLPACKAGE.EXE utility passing DB.dacpac
  • Add a call of the custom MSBuild Task to db.sqlproj file. For example:
<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 above is that custom MSBuild Task.

Thus the "Before-publish" script could be called from Visual Studio.

For CI we used a batch file (*.bat) where the same two utilities (SQLCMD.EXE & SQLPACKAGE.EXE) were called.

The final process we've got is a little bit complicated and should be described in a separate article - here I mentioned a direction only :)

like image 61
Vadim Loboda Avatar answered Sep 30 '22 20:09

Vadim Loboda


Move from using visual studio to using scripts that drive sqlpackage.exe and you have the flexibility to run scripts before the compare:

https://the.agilesql.club/Blog/Ed-Elliott/Pre-Deploy-Scripts-In-SSDT-When-Are-They-Run

ed

like image 30
Ed Elliott Avatar answered Sep 30 '22 20:09

Ed Elliott