Frage

Ich arbeite an einer Reihe von Delphi-Anwendungen, die müssen ihre eigenen Datenbankstrukturen im Bereich aktualisieren, wenn neue Versionen veröffentlicht werden und wenn Benutzer wählen, um zusätzliche Module zu installieren. Die Anwendungen sind eine Vielzahl von Embedded-Datenbanken (DBISAM und Jet zur Zeit, aber das kann sich ändern).

In der Vergangenheit habe ich dies getan, mit DBISAM die Benutzerversionsnummern verwenden, als mit jeder Tabelle gespeichert werden. Ich verschifft eine zusätzliche, leere Menge von Datenbank-Dateien und bei der Inbetriebnahme, verglichen die Versionsnummern der einzelnen Tabelle, die die FieldDefs mit der installierten Tabelle zu aktualisieren, falls erforderlich. Während dieses arbeitete, fand ich es ungeschickt eine Ersatzkopie der Datenbank und neueren Versionen von DBISAM transportieren müssen die Tabelle Umstrukturierungsmethodik geändert haben, so dass ich diese sowieso neu zu schreiben brauchen.

ich sehe zwei Wege zur Umsetzung dieses: eine Versionsnummer mit der Datenbank zu speichern und DDL-Skripten von älteren Versionen auf neuere Versionen zu erhalten oder um eine Referenzversion der Datenbankstruktur innerhalb der Anwendung zu speichern, die Referenz auf die Datenbank zu vergleichen bei der Inbetriebnahme, und mit der Anwendung generiert DDL die Datenbank aktualisieren Befehle.

Ich denke, dass ich wahrscheinlich Teile von beiden implementieren werden muß. Ich werde nicht die Anwendung will jedes Mal, wenn die Anwendung gestartet wird (zu langsam), um die Datenbank gegen die Referenzstruktur diff, so werde ich eine Datenbankstruktur Versionsnummer muß erkennen, ob der Benutzer eine veraltete Struktur verwendet. Allerdings bin ich nicht sicher, ob ich bereits geschriebene Skripte vertrauen kann die strukturelle Upgrade zu tun, wenn die Datenbank teilweise in der Vergangenheit aktualisiert worden sein könnte oder wenn der Benutzer sich geändert, um die Datenbankstruktur haben kann, so bin ich geneigt, eine zu verwenden, Referenz diff für die eigentliche Update.

Die Erforschung der Frage, die ich ein paar Datenbank Versionierung Tools gefunden haben, aber sie scheinen alle zu SQL Server gezielt und werden außerhalb der eigentlichen Anwendung implementiert. Ich bin für einen Prozess suchen, der in meine Anwendung integriert wird eng würde und dass auf unterschiedliche Datenbankanforderungen angepasst werden könnte (ich weiß, dass ich Adapter schreiben müssen würde, benutzerdefinierten abgeleiteten Klassen oder Ereigniscode Unterschiede in DDL Griff für verschiedene Datenbanken, das stört mich nicht).

Kennt jemand etwas aus dem Regal, die diese oder andernfalls der Fall ist, hat jemand irgendwelche Gedanken auf:

  1. Der beste Weg, um eine Referenzversion einer allgemeinen relationalen Datenbankstruktur innerhalb einer Anwendung zu speichern.

  2. Der beste Weg, um die Referenz gegen die eigentliche Datenbank Diff.

  3. Die beste Art und Weise DDL zu erzeugen, um die Datenbank zu aktualisieren.

War es hilfreich?

Lösung

Ich habe eine Blog-Post hier, wie ich dbisam Datenbank Versionierung und sQL Server .

Die wichtige Teile sind:

  

Da dbisam Ansichten nicht unterstützt,   die Versionsnummer gespeichert ist (zusammen   mit einem Haufen anderer info) in einem ini   Datei im Datenbankverzeichnis.

     

Ich habe ein Datenmodul,   TdmodCheckDatabase. Dies hat eine   TdbisamTable Komponente für jede Tabelle   in der Datenbank. Die Tabellenkomponente   enthält alle Felder in der Tabelle und   aktualisiert wird, wenn der Tisch   geändert.

     

Um Datenbank Änderungen vornehmen, die   folgende Verfahren verwendet wurde:

     
      
  1. Erhöhen Sie die Versionsnummer in der Anwendung
  2.   
  3. Erstellen und Test DB Änderungen.
  4.   
  5. Aktualisieren Sie die betroffenen Tabellen in TdmodCheckDatabase
  6.   
  7. Bei Bedarf (selten) in weiteren Upgrade-Abfragen   TdmodCheckDatabase. Z.B. setzen die   Werte neuer Felder oder neue hinzufügen   Datenzeilen.
  8.   
  9. Erstellen Sie eine Createeinheit Skript die mitgelieferte Datenbank   Werkzeuge.
  10.   
  11. Update Unit-Tests der neuen db anpassen
  12.   
     

Wenn die Anwendung ausgeführt wird, geht es   durch den folgenden Prozess

     
      
  1. Wenn keine Datenbank gefunden wird, dann laufen Create Einheit und dann tun   Schritt 3
  2.   
  3. Erhalten Sie die aktuelle Versionsnummer aus der Datenbank ini-Datei
  4.   
  5. Wenn es weniger als die erwarteten Versionsnummer dann     Run Create (erstellen alle neuen Tabellen)     Überprüfen Sie jede Tabellenkomponente in TdmodCheckDatabase     Wenden Sie alle Tabellenänderungen     laufen alle manuellen Upgrade-Skripte
  6.   
  7. Aktualisieren Sie die Versionsnummer in der Datenbank ini-Datei
  8.   

Ein Codebeispiel ist

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;

Andere Tipps

ähnliche Geschichte hier. Wir speichern eine DB-Versionsnummer in einer ‚System‘ Tabelle und prüfen, ob beim Start. (Falls die Tabelle / Feld / Wert nicht vorhanden ist, dann wissen wir, es ist Version 0, wo wir vergessen haben, dass etwas in hinzuzufügen!)

Während der Entwicklung, wie und wann wir brauchen die Datenbank aktualisieren wir einen DDL Skript schreiben, um die Arbeit zu tun, und einmal froh, dass es OK funktioniert es als Text-Ressource zu der App hinzugefügt wird.

Wenn die App feststellt, dass es zu aktualisieren braucht es die entsprechende Ressource lädt (n) und führt es / sie. Wenn es mehrere Versionen aktualisieren muss muss es jedes Skript ausführen, um. Es stellte sich heraus, um nur ein paar Zeilen Code in das Ende zu sein.

Der Haupt Punkt ist, dass anstelle die GUI-basierten Tool mit Hilfe von Tabellen in einer Ad-hoc oder ‚zufällig‘ Art und Weise zu ändern, schreiben wir tatsächlich die DDL sofort. Dies macht es viel einfacher, wenn die Zeit kommt, das vollständige Upgrade-Skript zu bauen. Und Struktur diff'ing ist nicht erforderlich.

Ich bin mit ADO für meine Datenbanken. Ich benutze auch eine Versionsnummer Schema, sondern nur als eine Plausibilitätsprüfung. Ich habe ein Programm, das ich entwickeln, das die Connection.GetTableNames und Connection.GetFieldNames verwendet eine Abweichung gegen ein XML-Dokument zu identifizieren, die die „Master“ Datenbank beschreibt. Wenn es eine Diskrepanz, dann baue ich die entsprechende SQL die fehlenden Felder zu erstellen. Ich lasse nie zusätzlich diejenigen.

Ich habe dann eine dbpatch Tabelle, die eine Liste von Patches durch einen eindeutigen Namen identifiziert enthält. Wenn es bestimmt Patches fehlt, dann werden sie angewandt und die entsprechende Datensatz wird die dbpatch Tabelle hinzugefügt. Meist geschieht dies ist neu gespeicherte Procs oder Feld Redimensionierung oder Indizes

Ich halte auch eine min-db-Version, die auch überprüft, da ich den Benutzern erlauben, eine ältere Version des Clients zu verwenden, lasse ich sie nur eine Version verwenden, das> ist = min-db-Version und <= cur-db-Version.

Was ich tue, ist in der Datenbank eine Versionsnummer speichern, und eine Versionsnummer in der Anwendung. Jedes Mal, ich brauche die Datenbankstruktur zu ändern, erstelle ich einige Code-Update, um die Struktur der Datenbank, und erhöhen Sie die Versionsnummer in der Anwendung. Wenn die Anwendung gestartet wird, vergleicht es, Zahlen und wenn läuft einige Code sein muss, um die Datenbankstruktur und aktualisiert die Datenbank der Versionsnummer zu aktualisieren. So ist die Datenbank nun mit der Anwendung auf dem Laufenden. Mein Code ist so etwas wie

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 läuft nur den notwendigen Code so etwas wie:

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

Sie können tatsächlich den gleichen Code verwenden, um die Datenbank von Grund auf neu erstellen

CreateDatabase;
for i := 1 to AppVersion do
  UpdateStructure(i);
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top