在过去,我使用DBISAM使用用户版本号完成此操作,而不是可以存储在每个表中.我发送了一组额外的空数据库文件,并在启动时使用FieldDefs比较每个表的版本号,以便在必要时更新已安装的表.虽然这有效但我发现必须运送数据库的备用副本并且更新版本的DBISAM已经改变了表重组方法,因此我无论如何都需要重写它.
我可以看到两种实现方法:使用数据库存储版本号并使用DDL脚本从旧版本获取更新版本或在应用程序内存储数据库结构的参考版本,比较启动时对数据库的引用up,让应用程序生成DDL命令来升级数据库.
我想我可能要实现两者的一部分.我不希望每次应用程序启动时应用程序都将数据库与引用结构区分开来(太慢),因此我需要一个数据库结构版本号来检测用户是否使用了过时的结构.但是,我不确定我可以信任预先编写的脚本来进行结构升级,因为过去数据库可能已经部分更新,或者用户可能自己更改了数据库结构,所以我倾向于使用实际更新的参考差异.
研究这个问题我发现了一些数据库版本控制工具,但它们似乎都是针对sql Server的,并且是在实际应用程序之外实现的.我正在寻找一个可以紧密集成到我的应用程序中的流程,可以适应不同的数据库需求(我知道我必须编写适配器,自定义后代类或事件代码来处理各种DDL的差异数据库,这不会打扰我).
有没有人知道任何现成的东西,或者没有做到这一点,有没有人有任何想法:
>在应用程序中存储通用关系数据库结构的引用版本的最佳方法.
>针对实际数据库区分引用的最佳方法.
>生成DDL以更新数据库的最佳方法.
解决方法
重要的部分是:
Because dbisam doesn’t support views,
the version number is stored (along
with a bunch of other info) in an ini
file in the database directory.I have a datamodule,
TdmodCheckDatabase. This has a
TdbisamTable component for every table
in the database. The table component
contains all fields in the table and
is updated whenever the table is
changed.To make database changes,the
following process was used:
- Increase the version number in the application
- Make and test DB changes.
- Update the affected tables in TdmodCheckDatabase
- If necessary (rarely) add further upgrade queries to
TdmodCheckDatabase. E.g. to set the
values of new fields,or to add new
data rows.- Generate a CreateDatabase unit script using the supplied database
tools.- Update unit tests to suit the new db
When the application is run,it goes
through the following process
- If no database is found,then run CreateDatabase unit and then do
step 3- Get the current version number from the database ini file
- If it is less than the expected version number then
Run CreateDatabase (to create any new tables)
Check every table component in TdmodCheckDatabase
Apply any table changes
run any manual upgrade scripts- Update the version number in the database ini file
代码示例是
class procedure TdmodCheckDatabase.UpgradeDatabase(databasePath: string; currentVersion,newVersion: integer); var module: TdmodCheckDatabase; f: integer; begin module:= TdmodCheckDatabase.create(nil); try module.OpenDatabase( databasePath ); for f:= 0 to module.ComponentCount -1 do begin if module.Components[f] is TDBISAMTable then begin try // if we need to upgrade table to dbisam 4 if currentVersion <= DB_VERSION_FOR_DBISAM4 then TDBISAMTable(module.Components[f]).UpgradeTable; module.UpgradeTable(TDBISAMTable(module.Components[f])); except // logging and error stuff removed end; end; end; for f:= currentVersion + 1 to newVersion do module.RunUpgradeScripts(f); module.sqlMakeIndexes.Execsql; // have to create additional indexes manually finally module.DBISAMDatabase1.Close; module.free; end; end; procedure TdmodCheckDatabase.UpgradeTable(table: TDBISAMTable); var fieldIndex: integer; needsRestructure: boolean; canonical: TField; begin needsRestructure:= false; table.FieldDefs.Update; // add any new fields to the FieldDefs if table.FieldDefs.Count < table.FieldCount then begin for fieldIndex := table.FieldDefs.Count to table.Fields.Count -1 do begin table.FieldDefs.Add(fieldIndex + 1,table.Fields[fieldIndex].FieldName,table.Fields[fieldIndex].DataType,table.Fields[fieldIndex].Size,table.Fields[fieldIndex].required); end; needsRestructure:= true; end; // make sure we have correct size for string fields for fieldIndex := 0 to table.FieldDefs.Count -1 do begin if (table.FieldDefs[fieldIndex].DataType = ftString) then begin canonical:= table.FindField(table.FieldDefs[fieldIndex].Name); if assigned(canonical) and (table.FieldDefs[fieldIndex].Size <> canonical.Size) then begin // field size has changed needsRestructure:= true; table.FieldDefs[fieldIndex].Size:= canonical.Size; end; end; end; if needsRestructure then table.AlterTable(); // upgrades table using the new FieldDef values end; procedure TdmodCheckDatabase.RunUpgradeScripts(newVersion: integer); begin case newVersion of 3: sqlVersion3.Execsql; 9: sqlVersion9.Execsql; 11: begin // change to DBISAM 4 sqlVersion11a.Execsql; sqlVersion11b.Execsql; sqlVersion11c.Execsql; sqlVersion11d.Execsql; sqlVersion11e.Execsql; end; 19: sqlVersion19.Execsql; 20: sqlVersion20.Execsql; end; end;