1

I have a sql server database working with a .net 2015 mvc 5 application. My database code is source controlled using SSDT project. I am using SqlPackage.exe to deploy database to the staging environment using .Decpac file created by the SSDT project build process. This has been done using a powershell task of VSTS build. This way I can make db schema changes in a source controlled way. Now the problem is regarding the master data insertion for the database.

I use a sql script file which have data insertion scripts which is executed as a post deployment script. This file is also source controlled.

The problem is that initially we have prepared the insertion script to target a sprint ( taking sprint n as a base) which works well for first release. but in next sprint if update some master data then how should the master data insert should be updated:

  1. Add new update / insert query at the last of the script file? but in this case the post deployment script will be execute by CI and it try to insert the data again and again in the subsequent builds which will eventually get failed if we have made some schema changes in the master tables of this database.
  2. Update the existing insert queries in the data insertion script. in this case also we have trouble because at the post build event, whole data will be re-inserted.
  3. Maintain separate data insertion scripts for each script and update the script reference to the new file for the post build event of SSDT. This approach has a manual effort and error pron because the developer has to remember this process. Also the other problem with this approach is if we need to setup 1 more database server in the distributed server farm. Multiple data insertion script will throw errors because SSDT has latest schema and it will create a database with the same. but older data scripts has data insertion for previous schema ( sprint wise db schema which was changed in later sprints)

So can anyone suggest best approach which have lesser manual effort but it can cover all the above cases.

Thanks Rupendra

Rupendra
  • 608
  • 2
  • 11
  • 42
  • We did it with multiple scripts that also checked to see if the values were already in the table. You'll probably need to version your scripts to work for newer versions of your schema if there are significant changes. Either that or you version your dacpacs/projects and release those incrementally. – Peter Schott Jun 14 '17 at 19:05
  • Have you get the answer which help you solve the problem? If yes, you can mark it as answer. And it will help others who have similar question. – Marina Liu Jun 28 '17 at 04:31
  • Hi @Marina-MSFT I haven't finalized this yet. Initially my view is to use Sprint wise SSDT file and a master data file for each sprint as a post build script. And I will run all the SSDT in an incremental fashion in case a full deployment required. But I need to test it. – Rupendra Jun 28 '17 at 09:43
  • Nice question :) – Ronnie Kapoor Jun 20 '18 at 04:58

3 Answers3

1

Make sure your pre- and post-deployment scripts are always idempotent. However you want to implement that is up to you. The scripts should be able to be run any number of times and always produce correct results. So if your schema changes that would affect the deployment scripts, well, updating the scripts is a dependency of the changes and accompanies it in source control. Versioning of your database is already a built in feature of SSDT. In the project file itself, there is a node for the version. And there is a whole slew of versioning build tasks in VSTS you can use for free to version it as well. When SqlPackage.exe publishes your project with the database version already set, a record is updated in msdb.dbo.sysdac_instances. It is so much easier than trying to manage, update, etc. your own home-grown version solution. And you're not cluttering up your application's database with tables and other objects not related to the application itself. I agree with keeping sprint information out of the mix. In our projects, I label source on successful builds with the build number, which of course creates a point in time marker in source that is linked to a specific build.

MikeZ
  • 11
  • 1
0

I would suggest to use MERGE statements instead of insert. This way you are protected for duplicated inserts within a sprint scope.

Next thing is how to distinguish different inserts for different sprints. I would suggest to implement version numbering to sync database with the sprints. So create a table DbVersion(version int). Then in post deployment script do something like this:

SET @version = SELECT ISNULL(MAX(version), 0) FROM DbVersion 
IF @version < 1
 --inserts/merge for sprint 1
IF @version < 2
 --inserts/merge for sprint 2
...
INSERT INTO DbVersion(@currentVersion)
scar80
  • 1,642
  • 2
  • 18
  • 36
  • i am trying some solutions and tools. Once I would tried your solution and if it worked well. I will mark it or revert back. thanks – Rupendra Jun 20 '17 at 09:56
  • You can find more details here: http://enterprisecraftsmanship.com/2015/08/18/state-vs-migration-driven-database-delivery/ – scar80 Jun 20 '17 at 12:57
0

What I have done on most projects is to create MERGE scripts, one per table, that populate "master" or "static" data. There are tools such as https://github.com/readyroll/generate-sql-merge that can be used to help generate these scripts.

These get called from a post-deployment script, rather than in a post-build action. I normally create a single (you're only allowed one anyway!) post-deployment script for the project, and then include all the individual static data scripts using the :r syntax. A post-deploy script is just a .sql file with a build action of "Post-Deploy", this can be created "manually" or by using the "Add New Object" dialog in SSDT and selecting Script -> Post-Deployment Script.

These files (including the post-deploy script) can then be versioned along with the rest of your source files; if you make a change to the table definition that requires a change in the merge statement that populates the data, then these changes can be committed together.

When you build the dacpac, all the master data will be included, and since you are using merge rather than insert, you are guaranteed that at the end of the deployment the contents of the tables will match the contents of your source control, just as SSDT/sqlpackage guarantees that the structure of your tables matches the structure of their definitions in source control.

I'm not clear on how the notion of a "sprint" comes into this, unless a "sprint" means a "release"; in this case the dacpac that is built and released at the end of the sprint will contain all the changes, both structural and "master data" added during the sprint. I think it's probably wise to keep the notion of a "sprint" well away from your source control!

Gavin Campbell
  • 796
  • 5
  • 19
  • i am trying some solutions and tools. Once I would tried your solution and if it worked well. I will mark it or revert back. thanks – Rupendra Jun 20 '17 at 09:56