首先,我在谈论这里的一种方法.我熟悉各种源控件应用程序,我熟悉Red Gate的sql Compare等工具,我知道如何编写一个应用程序来自动检查和控制源代码管理系统.如果有一个工具特别有助于提供一种全新的方法,或者具有有用和不常见的功能,那么很好,但是对于上面提到的任务,我已经设置好了.
我想要遇到的要求是:
>数据库模式和查找表数据进行版本控制
>用于更大表数据修复的DML脚本进行版本控制
>服务器可以从版本N升级到版本N X,其中X可能不总是为1
>代码在版本控制系统中不会重复 – 例如,如果我向表中添加一列,我不想确保更改在创建脚本和alter脚本中
>系统需要支持多个应用程序版本的多个客户端(试图将它们全部在1或2个版本中,但是还没有)
一些组织将增量更改脚本保留在其版本控制中,并从版本N到N 3,您将必须运行N> N 1的脚本,然后N 1> N 2,然后N 2-> N 3.一些的这些脚本可以是重复的(例如,列被添加,但后来更改为更改数据类型).我们试图避免重复性,因为一些客户端DB可能非常大,所以这些更改可能需要更长的时间.
一些组织将简单地在每个版本级别保留一个完整的数据库构建脚本,然后使用像sql Compare这样的工具将数据库带到其中一个版本.这里的问题是混合DML脚本可能是一个问题.想象一下,我添加一列,使用DML脚本来填充列,然后在列名更改的更新版本中.
也许有一些混合解决方案?也许我只是要求太多?任何想法或建议将不胜感激.
如果主持人认为这更适合作为社区维基,请让我知道.
谢谢!
解决方法
>数据库不需要从应用程序独立版本化
>所有数据库更新脚本应该是幂等的
因此,我不再创建任何类型的版本表.我只是添加更改到一个编号的.sql文件序列,可以在任何给定的时间应用,而不会破坏数据库.如果使事情变得更简单,我将为应用程序编写一个简单的安装程序屏幕,以便管理员可以随时运行这些脚本.
>所有模式更改都是通过脚本来完成的 – 没有GUI工作.
>必须特别注意确保所有键,约束等都被命名,以便在必要时可以由更高版本的脚本引用.
>所有更新脚本应检查现有条件.
最近一个项目的例子:
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;
在任何给定的时间,我可以在任何状态下针对数据库运行整个系列的脚本,并且知道现在可以使用当前版本的应用程序来加快事情的发生.因为一切都是脚本,建立一个简单的安装程序来做这个更容易,而且添加到源代码控制的架构更改根本就没有问题.