문제

새 버전이 출시 될 때 및 사용자가 추가 모듈을 설치하기로 선택할 때 현장에서 자체 데이터베이스 구조를 업그레이드 해야하는 여러 Delphi 응용 프로그램을 작업하고 있습니다. 응용 프로그램은 다양한 임베디드 데이터베이스 (DBISAM 및 JET 현재이지만 변경 될 수 있음)를 사용하고 있습니다.

과거에는 각 테이블에 저장할 수있는 것보다 사용자 버전 번호를 사용하여 DBISAM 으로이 작업을 수행했습니다. 추가로 빈 데이터베이스 파일 세트를 배송했으며 시작시 FieldDefs를 사용하여 각 테이블의 버전 번호를 비교하여 필요한 경우 설치된 테이블을 업데이트했습니다. 이것이 효과가 있었지만 나는 데이터베이스의 여분의 사본을 배송해야한다는 것이 어색하고 새로운 버전의 DBISAM이 테이블 구조 조정 방법론을 변경하여 어쨌든 다시 작성해야합니다.

이것을 구현하는 두 가지 방법을 볼 수 있습니다. 데이터베이스에 버전 번호를 저장하고 DDL 스크립트를 사용하여 이전 버전에서 최신 버전으로 이동하거나 응용 프로그램 내부의 데이터베이스 구조의 참조 버전을 저장하여 시작의 데이터베이스에 대한 참조를 비교합니다. UP 및 응용 프로그램이 DDL 명령을 생성하여 데이터베이스를 업그레이드합니다.

나는 아마 둘 다의 일부를 구현해야 할 것이라고 생각합니다. 응용 프로그램이 응용 프로그램이 시작될 때마다 (너무 느리게) 참조 구조에 대해 데이터베이스를 차단하기를 원하지 않으므로 사용자가 오래된 구조를 사용하고 있는지 여부를 감지하려면 데이터베이스 구조 버전 번호가 필요합니다. 그러나 과거에 데이터베이스가 부분적으로 업데이트되었을 때 또는 사용자가 데이터베이스 구조를 변경했을 때 데이터베이스가 부분적으로 업데이트되었을 때 사전 작성된 스크립트를 신뢰할 수 있는지 확신하지 못하므로 사용하려는 경향이 있습니다. 실제 업데이트에 대한 참조 Diff.

질문을 조사하면서 몇 가지 데이터베이스 버전화 도구를 찾았지만 모두 SQL Server를 대상으로하는 것처럼 보이며 실제 응용 프로그램 외부에서 구현됩니다. 나는 응용 프로그램에 엄격하게 통합 될 수있는 프로세스를 찾고 있으며 다양한 데이터베이스 요구 사항에 적합 할 수있는 프로세스를 찾고 있습니다 (다양한 데이터베이스 요구 사항에 적응할 수있는 프로세스를 찾고 있으며 다양한 데이터베이스 요구 사항에 적응할 수있는 프로세스를 찾고 있습니다. 데이터베이스, 그것은 나를 괴롭히지 않습니다).

누구든지 선반에서 벗어나거나 실패한 것에 대해 아는 사람이 있습니까?

  1. 일반적인 관계형 데이터베이스 구조의 참조 버전을 애플리케이션 내에 저장하는 가장 좋은 방법입니다.

  2. 실제 데이터베이스에 대한 참조를 차별하는 가장 좋은 방법.

  3. 데이터베이스를 업데이트하기 위해 DDL을 생성하는 가장 좋은 방법입니다.

도움이 되었습니까?

해결책

내가 어떻게하는지에 대한 블로그 게시물이 있습니다. DBISAM 데이터베이스 버전화 그리고 SQL 서버.

중요한 부분은 다음과 같습니다.

DBISAM은보기를 지원하지 않기 때문에 데이터베이스 디렉토리의 INI 파일에 버전 번호가 저장됩니다 (다른 정보와 함께).

데이터 모드, tdmodcheckdatabase가 있습니다. 이것은 데이터베이스의 모든 테이블에 대한 tdbisamtable 구성 요소가 있습니다. 테이블 구성 요소에는 테이블의 모든 필드가 포함되어 있으며 테이블이 변경 될 때마다 업데이트됩니다.

데이터베이스를 변경하기 위해 다음 프로세스가 사용되었습니다.

  1. 응용 프로그램의 버전 번호를 늘리십시오
  2. DB 변경을 만들고 테스트합니다.
  3. tdmodcheckdatabase에서 영향을받는 테이블을 업데이트하십시오
  4. 필요한 경우 (드물게) TDModCheckDatabase에 추가 업그레이드 쿼리를 추가하십시오. 예를 들어 새 필드의 값을 설정하거나 새로운 데이터 행을 추가합니다.
  5. 제공된 데이터베이스 도구를 사용하여 CreateAbase 장치 스크립트를 생성합니다.
  6. 새로운 DB에 맞게 단위 테스트를 업데이트하십시오

응용 프로그램이 실행되면 다음 과정을 거칩니다.

  1. 데이터베이스가없는 경우 CreateABASE 장치를 실행 한 다음 3 단계를 수행합니다.
  2. 데이터베이스 INI 파일에서 현재 버전 번호 가져 오기
  3. 예상 버전 번호보다 적은 경우 runeaTABase (새 테이블을 만들려면) 실행 tdModCheckDatabase의 모든 테이블 구성 요소를 확인하십시오. 테이블 변경 사항을 적용하여 수동 업그레이드 스크립트를 실행하십시오.
  4. 데이터베이스 INI 파일에서 버전 번호를 업데이트하십시오

코드 샘플입니다

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;

다른 팁

여기서 비슷한 이야기. DB 버전 번호를 '시스템'테이블에 저장하고 시작시 확인합니다. (테이블/필드/값이 존재하지 않으면 우리는 그것이 그 비트를 추가하는 것을 잊어 버린 버전 0이라는 것을 알고 있습니다!)

데이터베이스를 업그레이드해야 할 때 개발 중에 데이터베이스를 업그레이드해야 할 때 작업을 수행하기 위해 DDL 스크립트를 작성하고 일단 작동한다는 것이 행복해지면 앱에 텍스트 리소스로 추가됩니다.

앱이 업그레이드해야한다고 결정하면 적절한 리소스를로드하고 실행합니다. 여러 버전을 업그레이드 해야하는 경우 각 스크립트를 순서대로 실행해야합니다. 결국 몇 줄의 코드로 밝혀졌습니다.

요점은 GUI 기반 도구를 사용하여 테이블을 임시 또는 '무작위'방식으로 수정하는 대신 실제로 DDL을 바로 씁니다. 따라서 시간이 오면 전체 업그레이드 스크립트를 작성하기가 훨씬 쉬워집니다. 구조 차이가 필요하지 않습니다.

데이터베이스에 Ado를 사용하고 있습니다. 나는 또한 버전 번호 체계를 사용하지만 정신 점검으로 만 사용합니다. Connection.GetTableNames 및 Connection.GetFieldNames를 사용하여 개발 한 프로그램이 있습니다. "마스터"데이터베이스를 설명하는 XML 문서에 대한 불일치를 식별합니다. 불일치가있는 경우 누락 된 필드를 만들기 위해 적절한 SQL을 만듭니다. 나는 또 다른 것을 떨어 뜨리지 않습니다.

그런 다음 DBPatch 테이블이 있는데, 여기에는 고유 한 이름으로 식별 된 패치 목록이 포함되어 있습니다. 특정 패치가 누락 된 경우 적용되고 적절한 레코드가 DBPatch 테이블에 추가됩니다. 대부분 종종 이것은 새로운 저장 Procs 또는 Field 크기 조정 또는 색인입니다.

또한 Min-DB-Version을 유지합니다. 사용자가 클라이언트의 이전 버전을 사용할 수 있으므로 확인됩니다.> = min-db version 및 <= cur-db의 버전 만 사용할 수 있습니다. -버전.

내가하는 일은 데이터베이스에 버전 번호를 저장하고 응용 프로그램에 버전 번호를 저장하는 것입니다. 데이터베이스 구조를 변경해야 할 때마다 데이터베이스 구조의 구조를 업데이트하고 응용 프로그램의 버전 번호를 늘리면 코드 업데이트가 생성됩니다. 응용 프로그램이 시작되면 비교, 숫자 및 필요한 경우 데이터베이스 구조를 업데이트하기위한 코드가 필요합니다. 그리고 데이터베이스 버전 번호를 업데이트하십시오. 따라서 데이터베이스는 이제 응용 프로그램을 최신 상태로 유지합니다. 내 코드는 같은 것입니다

if DBVersion < AppVersion then
begin
  for i := DBVersion+1 to AppVersion do
    UpdateStructure(i);
end
else
  if DBVersion > AppVersion then
    raise EWrongVersion.Create('Wrong application for this database');

Updatestructure는 필요한 코드를 다음과 같은 것입니다.

procedure UpdateStructure(const aVersion : Integer);
begin
  case aVersion of
    1 : //some db code
    2 : //some more db code
    ...
    ...
  end;
  UpdateDatabaseVersion(aVersion);
end;  

실제로 동일한 코드를 사용하여 데이터베이스를 처음부터 만들 수 있습니다.

CreateDatabase;
for i := 1 to AppVersion do
  UpdateStructure(i);
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top