Gestion des versions de base de données dans les applications installées utilisant Delphi

StackOverflow https://stackoverflow.com/questions/1804464

Question

Je travaille sur un certain nombre d'applications Delphi qui devront mettre à niveau leurs propres structures de base de données sur le terrain lorsque de nouvelles versions seront publiées et lorsque les utilisateurs choisiront d'installer des modules supplémentaires. Les applications utilisent diverses bases de données intégrées (DBISAM et Jet actuellement, mais cela pourrait changer).

Auparavant, j’utilisais DBISAM avec les numéros de version de l’utilisateur pouvant être stockés avec chaque table. J'ai envoyé un ensemble supplémentaire de fichiers de base de données vide et, au démarrage, comparé les numéros de version de chaque table à l'aide de FieldDefs pour mettre à jour la table installée, si nécessaire. Bien que cela ait fonctionné, j’ai trouvé maladroit de devoir envoyer une copie de réserve de la base de données et les versions les plus récentes de DBISAM ont modifié la méthode de restructuration des tables, de sorte que je devrai le réécrire quand même.

Je vois deux façons de procéder: stocker un numéro de version dans la base de données et utiliser des scripts DDL pour obtenir des versions antérieures vers des versions plus récentes, ou stocker une version de référence de la structure de la base de données dans l'application, en comparant la référence à la base de données. au démarrage et que l'application génère des commandes DDL pour mettre à niveau la base de données.

Je pense que je devrai probablement implémenter des parties des deux. Je ne souhaite pas que l'application diffère la base de données par rapport à la structure de référence à chaque démarrage de l'application (trop lentement). Il me faut donc un numéro de version de structure de base de données pour détecter si l'utilisateur utilise une structure obsolète. Cependant, je ne suis pas sûr de pouvoir faire confiance à des scripts pré-écrits pour effectuer la mise à niveau structurelle lorsque la base de données aurait pu être partiellement mise à jour dans le passé ou lorsque l'utilisateur a lui-même modifié la structure de la base de données. Je suis donc enclin à utiliser référence de référence pour la mise à jour réelle.

A la recherche de la question, j'ai trouvé quelques outils de gestion de versions de base de données, mais ils semblent tous ciblés vers SQL Server et sont implémentés en dehors de l'application réelle. Je recherche un processus étroitement intégré à mon application et pouvant être adapté à différentes exigences de base de données (je sais que je devrai écrire des adaptateurs, des classes descendantes personnalisées ou un code d'événement afin de gérer les différences de DDL pour différents types de fichiers. bases de données, cela ne me dérange pas).

Est-ce que quelqu'un sait quelque chose dans le commerce qui fait ceci ou à défaut, est-ce que quelqu'un a des idées sur:

  1. Le meilleur moyen de stocker une version de référence d'une structure de base de données relationnelle générique dans une application.

  2. Le meilleur moyen de comparer la référence à la base de données réelle.

  3. Le meilleur moyen de générer du DDL pour mettre à jour la base de données.

Était-ce utile?

La solution

Je publie ici un article sur mon blog dbisam version des bases de données et serveur SQL .

Les parties importantes sont les suivantes:

  

Parce que dbisam ne supporte pas les vues,   le numéro de version est enregistré (avec   avec un tas d'autres informations) dans un ini   fichier dans le répertoire de la base de données.

     

j'ai un module de données,   TdmodCheckDatabase. Cela a un   Composant TdbisamTable pour chaque table   dans la base de données. Le composant de table   contient tous les champs de la table et   est mis à jour chaque fois que la table est   changé.

     

Pour modifier la base de données, le   le processus suivant a été utilisé:

     
      
  1. Augmentez le numéro de version dans l'application
  2.   
  3. Modifiez et testez les modifications de base de données.
  4.   
  5. Mettre à jour les tables affectées dans TdmodCheckDatabase
  6.   
  7. Si nécessaire, ajoutez (rarement) d’autres requêtes de mise à niveau à   TdmodCheckDatabase. Par exemple. pour définir le   valeurs de nouveaux champs, ou pour ajouter de nouveaux   lignes de données.
  8.   
  9. Génère un script d'unité CreateDatabase à l'aide de la base de données fournie   outils.
  10.   
  11. Mettez à jour les tests unitaires pour les adapter à la nouvelle base de données
  12.   
     

Lorsque l'application est lancée, elle passe   via le processus suivant

     
      
  1. Si aucune base de données n'est trouvée, exécutez l'unité CreateDatabase puis exécutez   étape 3
  2.   
  3. Obtenir le numéro de version actuel du fichier ini de la base de données
  4.   
  5. S'il est inférieur au numéro de version attendu, alors     Exécutez CreateDatabase (pour créer de nouvelles tables)     Vérifier chaque composant de la table dans TdmodCheckDatabase     Appliquer les modifications de table     exécuter des scripts de mise à niveau manuelle
  6.   
  7. Mettez à jour le numéro de version dans le fichier ini de la base de données
  8.   

Un exemple de code est

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;

Autres conseils

Histoire similaire ici. Nous stockons un numéro de version de base de données dans une table 'système' et le vérifions au démarrage. (Si la table / champ / valeur n'existe pas, nous savons que c'est la version 0 où nous avons oublié d'ajouter ce bit!)

Au cours du développement, au fur et à mesure que nous devons mettre à niveau la base de données, nous écrivons un script DDL pour effectuer le travail. Une fois heureux que tout fonctionne correctement, il est ajouté en tant que ressource texte à l'application.

Lorsque l'application détermine qu'elle doit être mise à niveau, elle charge les ressources appropriées et les exécute. S'il doit mettre à niveau plusieurs versions, il doit exécuter chaque script dans l'ordre. Il ne s’agit que de quelques lignes de code à la fin.

L’essentiel est que, au lieu d’utiliser les outils basés sur l’interface graphique pour modifier les tables de manière ad-hoc ou 'aléatoire', nous écrivons tout de suite le DDL. Cela facilite beaucoup, le moment venu, la création du script de mise à niveau complet. Et la structure diff'ing n'est pas nécessaire.

J'utilise ADO pour mes bases de données. J'utilise également un schéma de numéro de version, mais uniquement à des fins de vérification de l'intégrité. J'ai développé un programme qui utilise Connection.GetTableNames et Connection.GetFieldNames pour identifier toute divergence par rapport à un document XML décrivant le & "Master &"; base de données. S'il y a une différence, je construis le SQL approprié pour créer les champs manquants. Je n'en laisse jamais d'autres.

J'ai ensuite une table dbpatch, qui contient une liste de correctifs identifiés par un nom unique. S'il manque des correctifs spécifiques, ils sont appliqués et l'enregistrement approprié est ajouté à la table dbpatch. Il s’agit le plus souvent de nouveaux processus stockés, d’un redimensionnement de champs ou d’index

.

Je gère également une version min-db, qui est également cochée, car j'autorise les utilisateurs à utiliser une version plus ancienne du client. Je ne leur permets d'utiliser qu'une version > = min-db- version et < = cur-db-version.

Ce que je fais est de stocker un numéro de version dans la base de données et un numéro de version dans l'application. Chaque fois que je dois modifier la structure de la base de données, je crée du code, met à jour la structure de la base de données et augmente le numéro de version de l'application. Lorsque l'application démarre, elle compare, numérote et exécute éventuellement un code pour mettre à jour la structure de la base de données. AND met à jour le numéro de version de la base de données. Ainsi, la base de données est maintenant à jour avec l'application. Mon code est quelque chose comme

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 exécute simplement le code nécessaire, par exemple:

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

Vous pouvez réellement utiliser le même code pour créer la base de données à partir de zéro

CreateDatabase;
for i := 1 to AppVersion do
  UpdateStructure(i);
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top