MSSQL
For instructions on how to apply database migrations, please refer to the Getting Started documentation.
We recommend reading T-SQL Code Style since it has a major impact in how we write migrations.
SQL database project
The separate database definitions in src/Sql/.../dbo
serve as a "master" reference for the
intended and final state of the database at that time. This is crucial because the state of database
definitions at the current moment may differ from when a migration was added in the past. These
definitions act as a lint and validation step to ensure that migrations work as expected, and the
separation helps maintain clarity and accuracy in database schema management and synchronization
processes.
Additionally, a
SQL database project
is in place; however, instead of using the auto-generated migrations from
DAC,
we manually write migrations. This approach is chosen to enhance performance and prevent accidental
data loss, which is why we have both a sqlproj
and standalone migrations.
Modifying the database
In accordance with the tenets of Evolutionary Database Design every change must be considered as split into two parts:
- A backwards-compatible transition migration
- A non-backwards-compatible final migration
It is likely that a change does not require a non-backwards-compatible end phase e.g. all changes may be backwards-compatible in their final form; in that case, only one phase of changes is required. With the use of beta testing, partial roll-outs, feature flags, etc. the often-chosen path is to spread a change across several major releases with a calculated future state that can perform a "cleanup" migration that is backwards-compatible but still represents an overall-incompatible change beyond the boundaries of what we need for individual release safety.
Backwards compatible migration
- Modify the source
.sql
files insrc/Sql/dbo
. - Write a migration script, and place it in
util/Migrator/DbScripts
. Each script must be prefixed with the current date.
Please take care to ensure:
- any existing stored procedure accepts the same input parameters and that new parameters have nullable defaults
- when a column is renamed the existing stored procedures first check (coalesce) the new location before falling back to the old location
- continued updating of the old data columns since in case of a rollback no data should be lost
Non-backwards compatible migration
These changes should be written from the perspective of "all data has been migrated" and any old stored procedures that were kept around for backwards compatibility should be removed. Any logic for syncing old and new data should also be removed in this step.
- Remove the backwards compatibility that is no longer needed.
- Write a new Migration and place it in
src/Migrator/DbScripts_finalization
. Name itYYYY-0M-FinalizationMigration.sql
.- Typically migrations are designed to be run in sequence. However since the migrations in
DbScripts_finalization
can be run out of order, care must be taken to ensure they remain compatible with the changes toDbScripts
. In order to achieve this we only keep a single migration, which executes all backwards incompatible schema changes.
- Typically migrations are designed to be run in sequence. However since the migrations in
Upon execution any finalization scripts will be automatically moved for proper history.