I. Présentation

L'utilité d'une base de données n'est plus à démontrer de nos jours, où la grande majorité des applications y font appel pour le stockage et la manipulation d'informations.

Au cours de ce tutoriel, nous verrons en implémentant une application simple comment consulter et mettre à jour une liste de contacts, et ce sous Firebird SQL avec Delphi 2010.

II. Prérequis

 
Sélectionnez
SET SQL DIALECT 3; 

CREATE DATABASE 'localhost/3050:c:\dbexpressfirebird\bd_tuto.fdb' DEFAULT CHARACTER SET ISO8859_1 ;


/*  Generators or sequences */
CREATE GENERATOR GEN_T_CONTACT_CON_ID;


/* Table: T_CONTACT_CON, Owner: SYSDBA */
CREATE TABLE T_CONTACT_CON (CON_ID INTEGER NOT NULL,
        CON_EMAIL VARCHAR(64),
        CON_SITE_WEB VARCHAR(128),
        CON_NOM VARCHAR(30),
        CON_PRENOM VARCHAR(30),
        CON_TELEPHONE VARCHAR(30),
        CON_FAX VARCHAR(30),
        CON_ADRESSE VARCHAR(255),
        CON_COMMENTAIRES VARCHAR(255),
        CON_DATE_NAISSANCE DATE,
CONSTRAINT PK_T_CONTACT_CON PRIMARY KEY (CON_ID));
COMMIT WORK;
SET AUTODDL OFF;
SET TERM ^ ;

/* Stored procedures */
CREATE PROCEDURE SP_GEN_T_CONTACT_CON_ID RETURNS (ID INTEGER)
AS 
BEGIN EXIT; END ^

ALTER PROCEDURE SP_GEN_T_CONTACT_CON_ID RETURNS (ID INTEGER)
AS 
begin
  id = gen_id(gen_t_contact_con_id, 1);
  suspend;
end ^
SET TERM ; ^
COMMIT WORK ;
SET AUTODDL ON;
SET TERM ^ ;

/* Triggers only will work for SQL triggers */
CREATE TRIGGER T_CONTACT_CON_BI FOR T_CONTACT_CON 
ACTIVE BEFORE INSERT POSITION 0 
as
begin
  if (new.con_id is null) then
    new.con_id = gen_id(gen_t_contact_con_id,1);
end ^

COMMIT WORK ^
SET TERM ; ^

III. Installation de Firebird SQL

L'installation du serveur Firebird est très simple, il suffit d'exécuter le fichier d'installation et de suivre les étapes de l'assistant. Laissez toutes les options à leurs choix par défaut, mais pensez à cocher la case permettant de copier la bibliothèque fbclient.dll dans le répertoire système de la machine.

Quelques étapes importantes de l'installation en images :

choix du dossier de destination
Choix du dossier de destination

Il s'agit ici d'indiquer à l'installateur l'emplacement où seront copiés les fichiers du serveur Firebird.

choix des composants à installer
Choix des composants à installer
  • Composants serveur : dans le cas où le poste d'installation hébergera le serveur, cette option doit être cochée. Sous windows il est conseillé d'utiliser le super serveur, qui utilise un thread pour chaque nouvelle connexion, tandis que le serveur classique utilise un processus par connexion. Le mode serveur classique est préconisé pour un faible nombre de connexions tandis que pour un nombre élevé de connexions, c'est le mode super serveur qui est indiqué.
  • Composants outils développeur et administrateur : cette option doit être cochée, car nous allons utiliser l'outil ISQL. Elle permet aussi la copie de divers fichiers, tels que la base de données exemple employee.fdb.
  • Composants client : cette option installe les librairies requises pour se connecter au serveur firebird (librairie fbclient.dll par exemple).
tâches supplémentaires à effectuer par l'installateur
Tâches supplémentaires à effectuer par l'installateur
  • Utiliser Guardian pour contrôler le serveur : Guardian est un processus additionnel chargé de surveiller le processus serveur Firebird. Si ce dernier est arrêté suite à une défaillance, le Guardian va essayer de le relancer.
  • Modes d'exécution du serveur Firebird : l'exécution en tant qu'application fait tourner le processus Firebird sous le compte utilisateur actuellement connecté, tandis que l'exécution en tant que service fait tourner ce dernier sous le compte système local.
  • Exécuter automatiquement Firebird à chaque démarrage : cocher cette option revient à lancer le serveur automatiquement lors du démarrage de Windows.
  • Installer l'application du panneau de configuration : l'application du panneau de configuration est un petit utilitaire permettant de contrôler l'activité du serveur, et d'arrêter ou démarrer le serveur.
  • Copier la bibliothèque client Firebird dans le répertoire system : cette option donne l'accès à la bibliothèque cliente à toutes les applications installées.
  • Générer la bibliothèque gds32.dll pour les anciennes applications : le serveur Interbase, père de Firebird, utilise lui une bibliothèque client nommée gds32.dll. Pour rendre des applications utilisant cette dll compatibles à Firebird, cochez cette option.

Attention, l'application du panneau de configuration ne fonctionne pas sous Vista. Si vous êtes sur ce système d'exploitation, il faudra penser à décocher cette option.

fin de l'installatiion
Fin de l'installation

IV. Création de la base de données et de la table de Contacts

Pour créer notre base de données, nous allons utiliser ISQL. ISQL est un outil en ligne de commande permettant l'accès aux bases de données Firebird, utilisé principalement pour des tâches administratives. On peut l'utiliser pour créer ou supprimer une base de données par exemple.

exemple de création et suppression d'une base de données
Exemple de création et suppression d'une base de données


Enregistrez le script de création de la base de données sous c:\DBExpressFirebird\create_script.sql, puis lancez l'utilitaire ISQL.
Sous Windows XP, utilisez le menu Démarrer -> Tous les programmes -> Firebird -> Firebird ISQL Tool pour démarrer l'utilitaire, puis saisissez ensuite dans l'invite la commande :

IN c:\DBExpressFirebird\create_script.sql;

Puis, entrez la commande exit; pour sortir de l'utilitaire.

création de la base de données sous ISQL
Création de la base de données sous ISQL

Pensez à remplacer le chemin c:\dbexpressfirebird\ par le chemin d'accès à votre fichier de script.

Les noms des objets de notre base de données ont été normalisés en suivant les règles de nommage des objets que vous pouvez consulter à cette adresse http://sqlpro.developpez.com/cours/standards/

La base de données est créée. A présent passons à la création du projet sous Delphi 2010.

V. Création du projet sous Delphi 2010

La création d'un projet sous Delphi 2010 est similaire aux éditions précédentes, il faut faire Fichier -> Nouveau -> Applications Fiches VCL - Delphi. Un nouveau projet est créé, contenant un seul formulaire. Les propriétés du formulaire à changer sont celles-ci :

Propriété Valeur
Caption TUTORIEL FIREBIRD ET DELPHI 2010
Name FMain


Une fois cela fait, utilisez la combinaison des touches Ctrl+Shift+S pour enregistrer tout le projet. Nous avons choisi d'enregistrer le projet dans un dossier nommé c:\DBExpressFirebird, le formulaire a été sauvegardé sous le nom uMain.pas, et le projet sous le nom DBExpressFirebird.dpr.

A présent, le projet ayant été créé ainsi qu'un formulaire, nous allons mettre en place la connexion à la source de données.

V-A. Configuration de la connexion sous l'IDE

Pour configurer notre connexion, cliquez sur le menu Explorateur de données et choisissez l'option Ajouter une nouvelle connexion.

Si le menu explorateur de données ne s'affiche pas, cliquez sur un élément dans l'explorateur de données et réessayez.

Dans la boîte de dialogue qui s'ouvre, sélectionnez FIREBIRD comme fournisseur, et donnez un nom à la connexion. Ici nous avons choisi comme nom de connexion TUTO_D2010FB.

boîte de dialogue ajout d'une nouvelle connexion
Ajout d'une nouvelle connexion


La connexion est à présent créée, il faut maintenant la configurer. Pour ce faire, dans l'explorateur de données, développez le nœud FIREBIRD, faites un menu contextuel sur le nœud que l'on vient de créer et choisissez l'option modifier la connexion.

explorateur de données
Explorateur de données


Dans la première zone de texte, saisissez le chemin complet d'accès à la base de données, puis dans la seconde le nom de l'utilisateur, et enfin dans la troisième le mot de passe de l'utilisateur. Le tableau ci-dessous renseigne les valeurs utilisées :

Paramètre Valeur
Base de données localhost/3050:C:\DBExpressFirebird\BD_TUTO.FDB
Utilisateur sysdba
Mot de passe masterkey
modifier la connexion
Modifier la connexion


Cliquez ensuite sur tester la connexion pour s'assurer que les paramètres sont corrects et enfin, cliquez sur le bouton OK pour enregistrer la connexion. On peut dès à présent utiliser cette connexion.

Il se peut que le test ne fonctionne pas si vous n'avez pas installé la librairie client Firebird dans le répertoire système de Windows. Auquel cas, pour la suite du tutoriel, pensez à définir la propriété VendorLib du composant SQLConnection vers le chemin complet d'accès à la librairie fbclient.dll.

V-B. Connexion de l'application à Firebird SQL

Dans cette étape, nous allons connecter l'application à la base de données et accéder aux informations de la table T_CONTACT_CON afin d'afficher ses enregistrements dans une grille de données.

Nous allons maintenant relier notre fiche à la base de données. Mais avant voici les composants à utiliser pour y arriver, ainsi que leur rôle.

TSQLConnection : il permet de gérer la connexion à une base de données.
TSQLQuery : c'est le composant qui nous permettra d'exécuter des requêtes SQL sur la base de données.
TDataSetProvider : ce composant nous permettra d'accéder aux données du TSQLQuery et de résoudre les mises à jour que l'on y aura apportées vers le serveur de base de données.
TClientDataSet : nous utiliserons ce composant pour nous permettre principalement d'afficher les données lues du serveur dans une grille. Car il faut savoir que les composants dbExpress qui nous permettent de lire les données ne nous permettent pas au même titre que les autres descendants de TDataset de naviguer dans l'ensemble de données.
TDataSource : c'est ce dernier qui sera chargé d'effectuer la liaison entre nos composants orientés données, et notre jeu de données client (ici TClientDataSet).
TDBGrid : c'est le composant orienté données que nous avons choisi. Il nous permettra d'afficher nos données sous forme de grille éditable.

Passons à présent au design de notre formulaire. Déposez une instance de chacun des composants cités ci-dessus sur notre fiche.

l'IDE Insight peut aider grandement à le faire.

IDE insight
IDE insight


Le premier composant à configurer à présent est le SQLConnexion1. Définissez sa propriété ConnectionName au nom de la connexion que nous avons créée plus haut, soit tuto_d2010fb et définissez la propriété LoginPrompt à False (cela afin de nous éviter l'apparition d'une boîte de dialogue demandant la saisie du nom d'utilisateur et du mot de passe Firebird à chaque tentative de connexion à la base de données). Si la librairie cliente Firebird n'a pas été copiée dans le répertoire système, ou dans tout autre répertoire visible dans le PATH, modifiez également la propriété VendorLib pour indiquer l'emplacement du fichier fbclient.dll. Testez enfin le composant en mettant à True la valeur de sa propriété Connected.

Passons ensuite au composant SQLQuery1. On doit lui dire par quel composant SQLConnexion passer pour accéder à la base de données, pour cela définissez la propriété SQLConnection à SQLConnection1. Il faut également lui dire quelle requête SQL doit être exécutée. Pour ce faire, définir sa propriété SQL à "SELECT * FROM T_CONTACT_CON". Le composant devra donc retourner la liste complète des contacts enregistrés dans notre table T_CONTACT_CON. Mettez à True la propriété Active de SQLQuery1 pour s'assurer que la requête est bien exécutée.

Pour le DataSetProvider1, définissez sa propriété Dataset à SQLQuery1.

Définissez également la propriété ProviderName du ClientDataSet1 à DataSetProvider1, et mettez sa propriété Active à True pour s'assurer qu'il se connecte bien au SQLQuery1 via le DataSetProvider1.

Définissez la propriété DataSet du DataSource1 à ClientDataSet1.

Enfin, mettez la propriété DataSource du DBGrid1 à DataSource1. La grille affiche alors les colonnes correspondantes à notre requête SQL, ce qui signifie que la connexion s'est établie parfaitement.

Ci-dessous, vous avez le tableau récapitulatif de la configuration des composants utilisés :

Nom du composant Propriété Valeur
SQLConnection1 ConnectionName tuto_d2010fb
  LoginPrompt False
  VendorLib Fbclient.dll (ou chemin d'accès complet à la librairie)
  Connected True
SQLQuery1 SQLConnection SQLConnection1
  SQL SELECT * FROM T_CONTACT_CON
  Active True
DataSetProvider1 Dataset SQLQuery1
ClientDataSet1 ProviderName DataSetProvider1
  Active True
DataSource1 DataSet ClientDataSet1
DBGrid1 DataSource DataSource1


Au final, l'on doit avoir l'arborescence suivante dans la structure de notre fiche

structure de la fiche
Structure de la fiche


Enregistrez le projet et exécutez-le.

formulaire de l'application
Formulaire de l'application


La grille vous permet d'ores et déjà de créer et modifier des enregistrements. Néanmoins si l'on ferme et relance l'application toutes nos saisies ont disparues !

Par ailleurs, étant donné que nous avons créé un générateur pour le champ ID, nous ne devrions pas avoir à lui fournir de valeur manuellement. Cependant si vous tentez de créer une ligne sans lui fournir de valeur alors une exception requérant que le champ soit valué se déclenchera.

message d'erreur ID manquant
Message d'erreur

Qu'est ce qu'un générateur? C'est un numéroteur unique qu'on peut associer à un champ d'une ou plusieurs tables et obtenir ainsi des numéros uniques et automatiques (on parle d'auto-incrément sous d'autres SGBD). Nous en utilisons un dans notre table pour notre clé primaire.
Pour en savoir plus consulter la Faq FirebirdLes générateurs et l'article Les générateurs purs InterbaseLes générateurs purs Interbase

Pourquoi les données ne sont-elles pas conservées ? Eh bien, tout simplement parce que notre ClientDataSet1 est un ensemble de données en mémoire ! Toutes nos manipulations sont enregistrées en mémoire et ne sont pas répercutées sur la base de données. Lorsque l'on ouvre le ClientDataSet1, celui-ci via le DataSetProvider1 obtient les données du composant SQLQuery1 et les sauvegarde en mémoire vive. Toutes nos manipulations se font uniquement dans cette sauvegarde en mémoire vive, mais ne sont pas répercutées dans la base de données.

Nous allons à présent voir comment appliquer nos modifications vers la base de données.

V-C. Application des modifications en base de données

Ajoutez un nouveau bouton à la fiche, changez sa propriété Caption en "Appliquer les modifications". Double cliquez sur le bouton pour ouvrir son gestionnaire d'évènement OnClick et saisissez ce code :

delphi
Sélectionnez
procedure TFMain.Button1Click(Sender: TObject);
var
  n: Integer;
begin
  n := ClientDataSet1.ApplyUpdates(-1);
  ShowMessageFmt('Modification(s) appliquée(s), %d erreur(s) survenue(s)', [n]);
end;

Lancez le projet, enregistrez de nouveau quelques lignes et cliquez sur le bouton Appliquer les modifications. Vérifiez que les lignes ont été enregistrées en base de données en relançant de nouveau le projet.

V-D. Utilisation du générateur pour la clé primaire

Comme vous l'avez certainement remarqué, il faut à chaque fois spécifier une valeur pour la colonne ID qui est la clé primaire faute de quoi une exception est levée lorsque l'on veut enregistrer la ligne. Ayant pourtant créé un générateur pour cette clé primaire, l'on devrait s'attendre à ce que celle-ci soit renseignée automatiquement, au lieu de cela, on a une belle exception lorsqu'elle est absente lors de l'enregistrement.

Pour éviter l'exception et permettre d'avoir une clé générée automatiquement, nous allons modifier les propriétés du champ ID dans notre SQLQuery1.

Pour ce faire, double cliquez sur le composant SQLQuery1, faites un menu contextuel dans la petite boîte de dialogue qui est apparue et choisissez l'option ajouter tous les champs. Ensuite cliquez sur le champ CON_ID et mettez sa propriété Required à False.

liste des champs persistants
Liste des champs persistants

Enregistrez et exécutez le projet, saisissez une nouvelle ligne en omettant la valeur de la colonne ID et enregistrez la ligne (en changeant de ligne tout simplement). Aucune exception n'est levée !
Néanmoins, la valeur de la colonne ID n'est pas affichée, bien qu'elle ait été générée. Pour qu'elle s'affiche, il faut relire les enregistrements à partir du serveur. Dans la section suivante, nous allons au travers d'une synchronisation avec le serveur effectuer cette opération.

Notre générateur génère des nombres à partir de 1 en s'incrémentant à chaque fois. Si dans les enregistrements saisis précédemment vous en avez un avec l'ID à 1 par exemple, l'enregistrement va lever une exception car notre table n'autorise pas deux enregistrements avec le même ID.

V-E. Fonctionnement en mode déconnecté et enregistrement dans un fichier au format XML

Nous allons à présent rendre notre application indépendante de la base de données, c'est-à-dire que nous allons faire en sorte que l'on puisse continuer à faire des modifications dans notre liste de contacts, même si nous ne sommes pas connectés à la base de données. Pour cela nous utiliserons une fonctionnalité très intéressante du TClientDataSet, qui est de pouvoir enregistrer les informations qu'il a en mémoire dans un fichier. Le fichier peut être binaire ou au format XML.

La logique de notre application sera donc celle-ci : lorsque l'on ouvre l'application, l'on charge les données à partir du fichier XML. Un bouton nous permettra de faire la mise à jour des éventuelles modifications vers le serveur de base de données. Lors de la fermeture de l'application, ou lors du clic sur un bouton, on enregistrera nos données dans le fichier XML.

L'application fonctionnera donc en mode déconnecté, le seul moment où elle se connectera réellement à la base de données sera pour effectuer les mises à jour.

Mettez la propriété Connected du SQLConnection1 à False pour que l'application ne se connecte plus automatiquement à la base de données au démarrage.

Allez dans le gestionnaire de l'évènement OnCreate de la fiche et saisissez le code suivant :

delphi
Sélectionnez
procedure TFMain.FormCreate(Sender: TObject);
begin
  // charger les données du disque local
  if FileExists(ChangeFileExt(Application.ExeName, '.xml')) then
    ClientDataSet1.LoadFromFile(ChangeFileExt(Application.ExeName, '.xml'))
  else
  begin
    // on n'a pas encore de fichier xml, il faut le créer
    // activer le clientdataset active également le sqlquery qui à son tour
    // active le sqlconnection, si l'une des étapes échoue, une exception sera
    // levée
    try
      ClientDataSet1.Active := True;
      // sauvegarde des données lues dans un fichier xml
      ClientDataSet1.SaveToFile(ChangeFileExt(Application.ExeName, '.xml'), dfXML);
      // fermeture de la connexion à la base de données
      SQLConnection1.Close();
    except
      ShowMessage('Erreur lors de l''ouverture de la base de données');
    end;
  end;
end;

Puis celui-ci dans le gestionnaire de l'évènement OnClose de la fiche :

delphi
Sélectionnez
procedure TFMain.FormClose(Sender: TObject; var Action: TCloseAction);
begin
  // enregistrer les données sur le disque local
  ClientDataSet1.SaveToFile(ChangeFileExt(Application.ExeName, '.xml'), dfXML);
end;

Changez la propriété Caption du bouton Button1 à "Synchroniser" et modifiez le code de son gestionnaire d'évènement OnClick ainsi :

delphi
Sélectionnez
procedure TFMain.Button1Click(Sender: TObject);
var
  n: Integer;
begin
  try
    // se connecter au serveur de base de données
    SQLConnection1.Open();
    // synchronisation des données avec le serveur de base de données
    n := ClientDataSet1.ApplyUpdates(-1);
    ShowMessageFmt('Modification(s) appliquée(s), %d erreur(s) survenue(s)', [n]);
    // fermer et rouvrir le client dataset pour avoir les ID
    ClientDataSet1.Close();
    ClientDataSet1.Open();
    // fermer la connexion à la base de données une fois la synchronisation effectuée
    SQLConnection1.Close();
  except
    ShowMessage('Erreur lors de la synchronisation');
  end;
end;

Ajoutez un second bouton et mettez sa propriété Caption à "Enregistrer sur le disque", puis saisissez le code suivant dans son gestionnaire d'évènement OnClick

delphi
Sélectionnez
// enregistrer les données sur le disque local
ClientDataSet1.SaveToFile(ChangeFileExt(Application.ExeName, '.xml'), dfXML);

Vous pouvez saisir le code comme bon vous semble, sans le mettre en forme, ensuite utilisez la combinaison de touches Ctrl+D, ou faites menu Edition - Formatter le source pour mettre en forme tout votre code source, ou juste la portion de code sélectionnée.

Compilez le projet et exécutez-le. Lors du premier lancement, l'application essaie tout d'abord de charger les données depuis le fichier XML. Si celui-ci est absent du disque, l'application se connecte à la base de données, lit les données de la table et les enregistre dans le fichier XML, puis se déconnecte de la base de données. On peut ensuite saisir ou modifier les données dans la grille, celles-ci seront conservées en mémoire jusqu'au moment où l'on va invoquer l'enregistrement sur disque dans le fichier XML en fermant l'application ou en cliquant sur le bouton enregistrer sur disque. Les données sont mises à jour sur le serveur lorsque l'on clique sur le bouton synchroniser.

V-F. Gestion des erreurs lors des mises à jour

Peut-être ne l'avez-vous pas encore remarqué, mais il est possible que lors de notre synchronisation sur le serveur, des données aient changé par rapport à celles que nous avons enregistré dans notre fichier XML. Dans le cas où nous sommes les seuls à utiliser l'application, cette situation est impossible. Mais imaginez un instant que plusieurs personnes utilisent la même application, et qu'une seconde personne modifie le même enregistrement que vous. Que va-t-il se passer lors de la mise à jour ?

Le composant TClientDataSet a prévu des situations pareilles, et propose un évènement OnReconcileError pour gérer ces cas de figure. Mieux encore, Delphi dispose d'une boîte de dialogue toute prête chargée de la gestion des erreurs de réconciliation. Nous allons l'utiliser dans notre exemple.

Ajoutez recerror dans les uses de la section interface de notre unité. Puis créez un gestionnaire pour l'évènement OnReconcileError et ajoutez-y le code suivant :

delphi
Sélectionnez
procedure TFMain.ClientDataSet1ReconcileError(DataSet: TCustomClientDataSet;
  E: EReconcileError; UpdateKind: TUpdateKind; var Action: TReconcileAction);
begin
  // utiliser la boîte de dialogue de delphi pour réconcilier les erreurs
  Action := recerror.HandleReconcileError(DataSet, UpdateKind, E);
end;

Désormais lors de la synchronisation des données, pour chaque enregistrement modifié par rapport à la copie locale, la boîte de dialogue de réconciliation apparaîtra pour vous demander quoi faire.

boîte de dialogue de réconciliation d'erreur de mise à jour
Boîte de dialogue de réconciliation d'erreur de mise à jour

VI. Téléchargements

DBExpressFirebird.zip : les sources du projet
create_script.sql : le script de création de la base de données du projet
http://www.firebirdsql.org/index.php?op=files&id=engine_213 : la page de téléchargement du serveur Firebird SQL v 2.1.3
https://downloads.embarcadero.com/free/delphi : la page de téléchargement de la version d'évaluation de delphi 2010

VII. Conclusion

Tout au long de ce tutoriel, nous avons vu comment mettre facilement en œuvre une connexion à une base de données Firebird et l'utiliser grâce au tout nouveau driver dbExpress disponible avec delphi 2010.

VIII. Remerciements