Я боролся с этим в течение нескольких лет, прежде чем недавно принять стратегию, которая, кажется, работает довольно хорошо. Ключевые моменты, по которым я живу:
- База данных не требует независимой версии из приложения
- Все сценарии обновления базы данных должны быть идемпотентными
В результате я больше не создаю таблицы версий. Я просто добавляю изменения в пронумерованную последовательность файлов .sql, которые можно применить в любой момент без повреждения базы данных. Если все будет проще, я напишу простой экран установщика для приложения, чтобы позволить администраторам запускать эти сценарии в любое время.
Конечно, этот метод предъявляет несколько требований к дизайну базы данных:
- Все изменения схемы выполняются с помощью скрипта - без графического интерфейса.
- Особое внимание следует уделить тому, чтобы все ключи, ограничения и т. Д. Были названы так, чтобы на них можно было ссылаться в более позднем скрипте обновления, если это необходимо.
- Все сценарии обновления должны проверять существующие условия.
Примеры из недавнего проекта:
001.sql:
if object_id(N'dbo.Registrations') is null
begin
create table dbo.Registrations
(
[Id] uniqueidentifier not null,
[SourceA] nvarchar(50) null,
[SourceB] nvarchar(50) null,
[Title] nvarchar(50) not null,
[Occupation] nvarchar(50) not null,
[EmailAddress] nvarchar(100) not null,
[FirstName] nvarchar(50) not null,
[LastName] nvarchar(50) not null,
[ClinicName] nvarchar(200) not null,
[ClinicAddress] nvarchar(50) not null,
[ClinicCity] nvarchar(50) not null,
[ClinicState] nchar(2) not null,
[ClinicPostal] nvarchar(10) not null,
[ClinicPhoneNumber] nvarchar(10) not null,
[ClinicPhoneExtension] nvarchar(10) not null,
[ClinicFaxNumber] nvarchar(10) not null,
[NumberOfVets] int not null,
[IpAddress] nvarchar(20) not null,
[MailOptIn] bit not null,
[EmailOptIn] bit not null,
[Created] datetime not null,
[Modified] datetime not null,
[Deleted] datetime null
);
end
if not exists(select 1 from information_schema.table_constraints where constraint_name = 'pk_registrations')
alter table dbo.Registrations add
constraint pk_registrations primary key nonclustered (Id);
if not exists (select 1 from sysindexes where [name] = 'ix_registrations_created')
create clustered index ix_registrations_created
on dbo.Registrations(Created);
if not exists (select 1 from sysindexes where [name] = 'ix_registrations_email')
create index ix_registrations_email
on dbo.Registrations(EmailAddress);
if not exists (select 1 from sysindexes where [name] = 'ix_registrations_email')
create index ix_registrations_name_and_clinic
on dbo.Registrations (FirstName,
LastName,
ClinicName);
002.sql
/**********************************************************************
The original schema allowed null for these columns, but we don't want
that, so update existing nulls and change the columns to disallow
null values
*********************************************************************/
update dbo.Registrations set SourceA = '' where SourceA is null;
update dbo.Registrations set SourceB = '' where SourceB is null;
alter table dbo.Registrations alter column SourceA nvarchar(50) not null;
alter table dbo.Registrations alter column SourceB nvarchar(50) not null;
/**********************************************************************
The client wanted to modify the signup form to include a fax opt-in
*********************************************************************/
if not exists
(
select 1
from information_schema.columns
where table_schema = 'dbo'
and table_name = 'Registrations'
and column_name = 'FaxOptIn'
)
alter table dbo.Registrations
add FaxOptIn bit null
constraint df_registrations_faxoptin default 0;
003.sql, 004.sql и т. Д. *
В любой момент времени я могу запускать всю серию сценариев для базы данных в любом состоянии и знать, что с текущей версией приложения все сразу будет приведено в порядок. Поскольку все написано в сценариях, гораздо проще создать для этого простой установщик, и добавление изменений схемы в систему управления версиями не представляет никакой проблемы.