|
Interbase Ibx.Net - John COLIBRI.
|
- mots clé:tutorial - Interbase - Interbase Express .NET- Delphi 8 -
Vcl.Net
- logiciel utilisé: Windows XP, Delphi 8, Interbase 6.x, 7.x ou FireBird
1 ou 1.5
- matériel utilisé: Pentium 1.400Mhz, 256 M de mémoire
- champ d'application: Delphi 8 sur Windows, Bases de Données
- niveau: débutant Delphi et Base de Données
- plan:
1 - Introduction
Cet article va vous indiquer comment utiliser le Serveur Interbase fourni
avec Delphi en utilisant le version 8 de Delphi. Ce tutorial a plusieurs
objectifs:
- vous présenter comment réaliser des applications utilisant des bases de
données Sql en Delphi 8. Tous les exemples ont été codés et les sources sont
téléchargeables.
- effectuer toutes les opérations en Delphi, au lieu d'utiliser des outils
annexes tels que WISQL ou IbConfig
- présenter surtout la partie accès aux données, sans entrer dans le menu
détail de la partie visuelle (dbGrid, dbEdit)
Nous nous adressons pour cet article à un programmeur Delphi ayant une idée
élémentaire de Delphi: Palette, Inspecteur, OnClick. Tout le reste sera
expliqué.
Nous supposons:
- que Delphi 8 est installé (la version "développeur": pas la version
"étudiant" qui n'a pas les bases de données, et pas besoin de la version
"Entreprise" ou "Architecte", mais tout marche aussi avec ces deux
dernières)
- qu'Interbase est installé (voyez le tutorial
interbase qui détaille cette installation). J'ai utilisé la version
Interbase que j'ai installé et que j'utilise couremment avec Delphi 6,
mais tout fonctionne bien sûr avec les versions 7 et FireBird.
3 - Les différentes possibilités
Cet article fait part d'une série décrivant les différentes possibilités de
gérer des données Interbase en Delphi 6 et Delphi 8. Il convient donc tout
d'abord de resituer les différentes possibilités de traitement proposées en
Delphi:
- la gestion de tables Interbase se fait en utilisant un Serveur et un
Client fournis par Interbase (et livré avec Delphi). Ceux-ci peuvent être
situés sur des PC différents ou sur le même PC. Pour la simplicité des
figures, nous supposerons qu'ils sont sur des PC distincts.
- le Client Interbase ne sait pas gérer tout seul les données. Il faut
écrire des applications qui lui envoient des requêtes. Nous pouvons écrire
ces applications avec n'importe quel langage qui sait communiquer avec le
Client Interbase. Pour notre part nous utiliserons Delphi:
- Delphi offre plusieurs modules pour communiquer avec le Client Interbase:
- en Delphi 4 à Delphi 6, le mode le plus ancien et le plus efficace est
Interbase Express (alias IBX).
- en Delphi 6 nous pouvious aussi utiliser dbExpress (alias Midas, alias
DataSnap, alias client léger ou programmation multi-niveau):
- en Delphi 8, Borland a prévu deux modes de programmation:
- le mode VCL.NET qui fournit une programmation pratiquement identique
à la programmation sous Delphi 6, mais par dessus la librairie .NET
(au lieu d'être par dessus la librairie Win32).
Sous VCL.NET
- Borland a porté la librairie IBX sous Delphi 8, et c'est l'objet
de notre article
- Ainsi que la mécanique générique (indépendante d'Interbase),
dbExpress.Net
- Delphi 8 permet aussi d'utiliser les contrôles .NET (les boutons,
les listbox etc). Dans ce cas, nous devons utiliser les couches
d'accès aux données fournies par Microsoft. Deux modes:
- Ado.Net qui est un mode similaire à dbExpress, à la Microsoft
- le Borland Data Provider qui est une mise en forme de Ado.Net
plus efficace et bien plus conviviale. Elle aussi ressemble fort à
dbExpress, mais en "plus Delphi" que la librairie précédente
Par rapport à ces architectures, voici les articles que vous pouvez consulter
ici:
- le tutorial interbase: comment utiliser des bases
de données en mode Client Serveur (Delphi 6, Ibx). L'article
d'initiation le plus complet
- Interbase dbExpresss: le mode dbExpress
(Delphi 6, dbExpress). Le mode qui permet le mieux de comprendre
l'architecture Ado.Net qui en est directement issue
- Interbase Ibx.Net: le portage sous .Net de la mécanique Ibx (Delphi 8,
Ibx.Net). Le moyen le plus simple d'utiliser Interbase et Delphi 8.
C'est cet article ci.
- Interbase dbExpress.Net: le portage sous
.Net de la mécanique dbExpress (Delphi 8, dbExpress.Net). L'utilisation
des techniques VCL pour Interbase ET pour les autres serveurs (Oracle,
Sql Server, MyBase etc)
- Delphi 8 Ado.Net: sous Windows Forms, en
l'absence de couche spécifique à Interbase nous pouvons utiliser une
mécanique similaire à Odbc et proche d'Ado sous Win32. Cet article
présente ce fonctionnement
- Interbase Borland Data Provider:
la voie royale sous Windows Forms, et pour toutes les base, même pour tous
les langages
Je crois qu'il vaut mieux lire les articles dans cet ordre, mais vous êtes
libre de consulter ce qui vous convient le mieux, quitte à revenir à un autre
article au besoin.
Mentionnons au'Interbase peut aussi être utilisé comme moyen de sauvegarde
sous ECO, et comme source de données de pages Asp.Net et de Services Web.
Si après ces saines lectures vous souhaitez approfondir vos connaissances, nous
serons heureux de vous acueillir lors de nos formations ou
de fournir telles prestations de programmation de portage ou d'assistance que
vous jugerez utile.
4 - Créer la Base
4.1 - Installation
Comme indiqué au début de cet article, je ne présente pas à nouveau
l'installation d'Interbase, pas plus que celle de Delphi 8.
4.2 - Création de la base
Nous allons créer une base contenant les stages offerts par l'Institut Pascal.
Nous placerons cette base dans le répertoire "..\data\" (situé au même niveau
que le .EXE. Le .ZIP téléchargeable créera ce répertoire automatiquement). Le
nom du fichier sera "Institut_Pascal.GDB".
Pour créer la base:
|
créez une nouvelle application et appelez-la "p_net_ibx_create_base_3"
|
|
sélectionnez dans la page "Interbase" de la Palette le composant
tIbTransaction:
et posez ce composant sur la tForm
|
|
sélectionnez de même une tIbDatabase (situé juste au dessus du précédent
dans notre figure et placez-la sur la tForm
|
|
initialisez IbDatabase1.DefaultTransaction vers IbTransaction1
|
|
utilisez un tButton pour créer la base:
- placez un tButton, nommez-le create_base_, et créez sa méthode OnClick
- voici le code de cette méthode:
procedure TForm2.create_database_Click(Sender: TObject);
begin
IbDatabase1.Close;
with IbDatabase1 do
begin
If FileExists(k_database_path+ k_database_name)
Then begin
display('Erase');
Exit;
end;
DatabaseName:= k_database_path+ k_database_name;
SqlDialect:= 3;
with Params do
begin
Clear;
Add('USER "sysdba"');
Add('PASSWORD "masterkey"');
Add('PAGE_SIZE 4096');
end;
display('create');
CreateDatabase;
end; // with IbDatabase1
end; // create_database_Click
|
|
|
compilez et exécutez
|
|
cliquez Button1
|
|
Delphi 8 crée la base
|
En fait ce n'est pas tout à fait exact. Avec ma version actuelle de Delphi, la
création est refusée:
Une recherche Google indique que cette erreur est connue:
Et comme nous l'avons déjà écrit, ce type d'erreur est semble-t-il assez
courant et redouté. Dans le fichier "Delphi 8 2nd Update", Borland cite de
nombreuses corrections ayant eu pour objet de faire disparaître ce type de
messages. Pour le moment je ne comprends pas ce qui les provoque.
Une recherche Google "Object Reference not Set" fournit 12.400 réponses, les
victimes allant de Crystal Report à Excel.
Si vous avez une version plus récente que nous de Delphi 8, il est certain que
cette erreur aura été corrigée.
En attendant, pour poursuivre l'exposé, nous vous suggérons:
- de copier dans le répertoire .._DATA une base de votre choix. Nous avons
copié la base INSTITUT_PASCAL.GDB provenant de
Tutorial Interbase. Vous pouvez d'ailleurs
utiliser le .ZIP de ce Tutorial pour créer sous Delphi 6 une base vierge à
l'emplacement de votre choix. Vous pouvez aussi rechercher sur disque
EMPLOYEE.GDB qui est la base de démonstration Interbase, et la copier dans
ce répertoire.
- de renommer la base INSTITUT_PASCAL_3.GDB (le changement de nom via un
Explorateur Windows est permis)
Vous pouvez télécharger ce projet "net_ibx_create_database_3.zip".
Maintenant que nous disposons d'une base, nous allons utiliser les composants
Ibx.Net pour accéder aux données de notre base.
4.3 - Connection à une base
Pour nous connecter à une base Interbase nous allons utiliser une seconde
IbDatabase:
Ce composant doit être initialisé avec:
- dans DataBaseName, la chaîne de connection qui est
- si nous travaillons en local, le chemin:
c:\programs\interbase\data\Institut_Pascal_3.gdb
ou
..\data\Institut_Pascal_3.gdb
- l'URL du PC qui héberge le Serveur:
127.0.0.1\
c:\programs\interbase\data\Institut_Pascal_3.gdb
HostName\
c:\programs\interbase\data\Institut_Pascal_3.gdb
www.jcolibri.com\
c:\programs\interbase\data\Institut_Pascal_3.gdb
- dans Params, les paramètres propres à Interbase. Dans notre cas, les
paramètres par défaut du Serveur, plus le nom d'utilisateur et le mot de
passe.
Une fois les propriétés initialisées, nous pouvons tester la connection en
basculant tIbDatabase.Connected sur True.
A titre de vérification:
|
posez un second tIbDataBase sur la forme
|
|
initialisez IbDatabase2.DatabaseName avec
..\data\Institut_Pascal_3.gdb
|
|
cliquez deux fois sur IbDatabase2 pour ouvrir l'éditeur de tIbDatabase
|
|
Delphi présente le dialogue suivant:
|
|
sélectionnez "User Name" et tapez SYSDBA
|
|
sélectionnez "Password" et tapez masterkey
|
|
supprimez la coche de "Login Prompt"
|
|
cliquez le bouton "Test"
|
|
le résultat est:
|
|
fermez l'éditeur en cliquant "Ok"
|
Notez que:
- la connection est le test IMPERATIF pour vérifier que nous pouvons
travailler en Interbase. Nous recommandons d'effectuer cette connection
systématiquement avant de poser des tonnes de composants sur la tForm ou
d'écrire des milliers de lignes
- si nous connectons la base en mode conception, Delphi ouvrira aussi la base
lorsque l'exécution sera lancée. Ces deux connections sont comptabilisés par
le gestionnaire de licences Interbase comme 2 connections séparées (ce sont
bien deux processus Windows). Si vous travaillez en utilisant la version
Delphi d'Interbase, il vaut mieux fermer la connection en mode conception,
puis la rouvrir lors de l'exécution par:
tIbDatabase.Open;
5 - Créer une Table
Nous allons créer une table contenant pour chaque formation:
- un code (par exemple 8)
- un nom (par exemple "Delphi Interbase")
- un prix (par exemple 1.400)
Pour cela nous devons envoyer une requête en langage SQL vers le Serveur
Interbase.
La syntaxe de cette requête est:
CREATE TABLE formations_3
(f_numero INTEGER, f_nom CHARACTER(25), f_jours
INTEGER, f_prix NUMERIC(5, 2) )
|
Il suffit donc de choisir un nom de table, et le nom de chaque colonne avec son
type.
Parmi les types autorisés par Interbase citons:
- INTEGER pour les valeurs entières 32 bits
- SMALLINT pour les valeurs entières 16 bits
- NUMERIC(decimales, précision) pour une valeur numérique flottante
- DATE pour une date
- CHARACTER(taille) pour des caractères
Pour envoyer cette requête vers le Serveur:
- nous utilisons un tIbDataBase qui assurera la connection vers le Serveur
- nous utilisons un tIbSql
- nous le relions à tIbDatabase
- nous plaçons la requête SQL dans sa propriété IbSql.SQL (via
l'Inspecteur ou en code)
- nous appelons tIbSql.ExecQuery
- la création n'est visible par tout le monde que si la transaction qui est
utilisée pour la création de la table est confirmée
En Interbase, toutes les requêtes sont créées dans le cadre d'une transaction.
Les transaction sont un mécanisme qui garantit que plusieurs sont réalisées en
entier ou annulées. L'archétype est le transfert bancaire: si nous débitons
DUPOND pour créditer MARTIN, le système doit garantir que soit les deux
modifications sont réalisée ou aucune ne l'est.
En Delphi, les composants de bases de données utilisent par défaut des
transactions transparentes pour le programmeur, mais nous pouvons gérer les
transactions nous-même. C'est ce qui est recommandé pour Interbase.
En InterbaseExpress, nous utilisons un composant tIbTransaction que nous
connectons à tIbDatabase.DefaultTransaction. Les primitives sont:
- tIbTransaction.StartTransaction pour démarrer une nouvelle transaction
avant une ou plusieurs opérations
- tIbTransaction.Commit pour confirmer la suite d'opération, ou
tIbTransaction.RollBack pour tout annuler.
- StartTransaction et Commit ou RollBack sont souvent utilisés dans TRY
EXCEPT:
TRY
IbTransaction1.StartTransaction;
débite DUPOND
crédite MARTIN
IbTransaction1.Commit;
EXCEPT
IbTransaction1.RollBack;
END;
|
Nous ne pouvons appeler IbTransaction1.StartTransaction si la transaction
attachée à IbTransaction1 est fermée (committed ou Rolledback). Pour savoir si
une transaction est active, nous pouvons utiliser la fonction InTransaction.
Ainsi:
IF NOT IbTransaction1.InTransaction
THEN IbTransaction1.StartTransaction;
|
Que se passerait-il si nous réalisons le traitement sans cette IbTransaction:
- pendant l'exécution de notre application d'autres applications
(l'explorateur de bases de données, un autre de nos exe) ne "verraient" pas
la table
- un autre IbQuery de notre propre application pourrait ne pas voir la table
- lorsque l'EXE sera fermé, la transaction sera automatiquement fermée
Le plus simple est donc d'utiliser Commit.
Voici à présent l'application:
|
créez une nouvelle application et appelez-la "net_ibx_create_table"
|
|
placez un tIbDataBase sur la Forme. Cliquez deux fois sur IbDataBase1,
renseignez "local", "DataBase", "User Name" "Pass Word" et "Login Prompt".
Vérifiez la connection en cliquant "Test", puis fermez l'Editeur de
Connection en cliquant "OK". La connection sera ouverte avant l'envoi de
la requête
|
|
placez un tIbTransaction sur la Forme, et reliez
IbDatabase1.DefaultTransaction
|
|
placez un tIbSql sur la tForme
|
|
sélectionnez sa propriété DataBaseName et initialisez-la à
IbDataBase1
|
|
placez un tButton sur la Forme et créez sa méthode OnClick. Placez-y les
instructions de création:
|
procedure TForm2.create_table_Click(Sender: TObject);
begin
with IbSql1 do
begin
Close;
with Sql do
begin
Clear;
Add('CREATE TABLE '+ k_table_name);
Add(' ('
+' f_numero INTEGER,');
Add(' f_nom CHAR(25),');
Add(' f_jours SMALLINT,');
Add(' f_prix NUMERIC(5, 2)');
Add(' )');
end; // with Sql
Try
IbDatabase1.Open;
display(IbDatabase1.DefaultTransaction.Name);
if IbDatabase1.DefaultTransaction.Active
then display('active')
else display('closed');
display('Commit_previous');
if ibtransaction1.InTransaction
then ibTransaction1.Commit;
display('StartTransaction');
ibtransaction1.StartTransaction;
if IbDatabase1.DefaultTransaction.Active
then display('active')
else display('closed');
display('Exec');
ExecQuery;
display('Commit');
ibtransaction1.Commit;
display(' ok');
except
on e: Exception do
display(' *** pb_create '+ e.Message);
end;
end; // with IbSql1
end; // create_database_Click
|
|
compilez, exécutez, et cliquez le bouton
|
Vous pouvez télécharger le sources du projet "ib_create_table.zip".
5.1 - Vérifier la création
Nous pouvons vérifier que la création a été effectuée en utilisant
l'explorateur de bases de données Delphi, ou en lisant les données ce cette
table dans notre application.
Pour lire les données il suffit d'envoyer la requête
|
SELECT * FROM formations_3
|
au moteur. Nous verrons cette requête SELECT en
détail plus bas, mais voici comment procéder pour notre test:
|
ajoutez un composant tIbQuery sur la tForme
|
|
sélectionnez sa propriété DataBaseName et initialisez-la à
IbDataBase1
|
|
placez un second tButton sur la Forme et placez-y la requête de lecture:
|
procedure TForm2.select_Click(Sender: TObject);
begin
with IbQuery1 do
begin
Close;
with Sql do
begin
Clear;
Add('SELECT * FROM '+ k_table_name);
Try
Open;
except
on e: Exception do
display(' *** pb '+ e.Message);
end;
end; // with Sql
end; // with IbQuery1
end; // select_Click
|
|
compilez, exécutez, et cliquez le bouton
|
5.2 - Effacer une table
Pour supprimer une Table, il faut exécuter la requête:
Donc:
|
placez un autre tButton sur la Forme et placez-y la requête de
suppression:
|
procedure TForm2.drop_Click(Sender: TObject);
begin
IbDatabase1.Open;
with IbSql1 do
begin
Close;
with Sql do
begin
Clear;
Add('DROP TABLE '+ k_table_name);
end; // with Sql
Try
if ibtransaction1.InTransaction
then ibTransaction1.Commit;
ibtransaction1.StartTransaction;
ExecQuery;
ibtransaction1.Commit;
display(' ok');
except
on e: exception do
display(' *** pb_drop '+ e.Message);
end;
end; // with IbSql1
end; // drop_Click
|
|
compilez, exécutez, et cliquez le bouton
|
Notez que:
- nous avons utilisé un IbSql pour les requêtes qui modifient les données et
un IbQuery `pour la lecture. La raison est que IbSql en fait que faire
transiter la requête vers le moteur, alors que IbQuery tamponnne les
résultats provenant du Serveur
- notez toutefois, que pour envoyer une requête de modification il faut
utiliser soit tIbsql.ExecQuery ou tIbQuery.ExecSql, et pour la lecture
c'est tIbQuery.Open.
tIbQuery.Open est équivalent à tIbQuery1.Active:= True (mais pas à
ExecSql). Comme l'Inspecteur propose Active (pour pouvoir positionner ses
éléments visuels), nous pouvons ouvrir une Table depuis l'Inspecteur, mais
nous ne pouvons pas créer de Table en mode conception (il faut exécuter du
code)
Vous pouvez télécharger le source du projet "net_ibx_create_table.zip".
Dans l'article Interbase Tutorial vous trouverez
des exemple pour ajouter plusieurs tables à partir d'un schéma placé dans un
fichier .TXT. Ibx.Net offre aussi un tout nouveau composant tIbScript.
6 - Ajouter des Données
6.1 - Ajout simple
Ajoutons un enregistrement pour le stage
3, Interbase Delphi
L'instruction SQL est:
INSERT INTO formations_3
(f_numero, f_nom)
VALUES (3, 'Interbase Delphi')
|
L'ajout d'enregistrement va modifier les données du Serveur, donc nous
utiliserons tIbSql.ExecQuery ou tIbQuery.ExecSql.
De façon détaillée:
|
créez une nouvelle application et nommez-la "ib_insert_data"
|
|
placez un tIbTransaction sur la Forme
|
|
placez un tIbDataBase sur la Forme. Cliquez deux fois sur IbDataBase1,
renseignez "local", "DataBase", "User Name" "Pass Word" et "Login Prompt".
Vérifiez la connection en basculant IbDataBase1.Connected sur True, puis
fermez la connection.
Sélectionnez DefaultTransaction et initialisez-la à IbTransaction1
|
|
placez un tIbSql sur la tForme
|
|
sélectionnez sa propriété DataBaseName et initialisez-la à IbDataBase1
|
|
placez un tButton sur la Forme et créez sa méthode OnClick. Placez-y les
instructions d'ajout:
procedure TForm2.insert_data_Click(Sender: TObject);
// -- hard coded values
begin
with IbSql1 do
begin
Close;
with Sql do
begin
Clear;
Add('INSERT INTO '+ k_table_name);
Add(' (f_numero, f_nom)');
Add(' VALUES (3, ''Delphi Interbase'')');
end; // with Sql
display_strings(Sql);
Try
IbDatabase1.Open;
if ibtransaction1.InTransaction
then ibTransaction1.Commit;
ibtransaction1.StartTransaction;
ExecQuery;
ibtransaction1.Commit;
display(' ok');
except
on e: Exception do
display(' *** pb_create '+ e.Message);
end;
end; // with IbSql1
end; // insert_data_Click
|
|
|
compilez, exécutez, et cliquez le bouton
|
Pour avoir un peu plus de données nous avons ajouté une procédure qui insère
quelques lignes à la fois.
La procédure qui effectue cet ajout est la suivante:
procedure TForm2.insert_many_Click(Sender: TObject);
// -- insert several hard coded values in a row
procedure insert_generic(p_number: Integer; p_name: String; p_days: Integer; p_cost: Double);
begin
with Form2, IbSql1 do
begin
IbDatabase1.Open;
Close;
with Sql do
begin
Clear;
Add('INSERT INTO '+ k_table_name);
Add(' (f_numero, f_nom, f_jours, f_prix)');
DecimalSeparator:= '.';
Add(' VALUES ('+ IntToStr(p_number)+ ', '+ QuotedStr(p_name)
+ ', '+ IntToStr(p_days)+ ', '+ FloatToStr(p_cost)+ ')');
DecimalSeparator:= ',';
end;
display_strings(Sql);
Try
if not IbTransaction1.InTransaction
then IbTransaction1.StartTransaction;
ExecQuery;
IbTransaction1.Commit;
display(' ok');
except
on e: Exception do
display(' *** pb_insert '+ e.Message);
end;
end; // with IbSql1
end; // insert_generic
begin // // insert_automatic_Click
IbDatabase1.Open;
insert_generic(1, 'Initiation Delphi', 3, 1400.40);
insert_generic(2, 'Bases de Données Delphi', 3, 1400);
insert_generic(3, 'Interbase Delphi', 3, 1400);
insert_generic(4, 'Composants Delphi', 3, 1400);
insert_generic(5, 'UML et Patterns en Del', 3, 1400);
insert_generic(6, 'Initiation Pascal', 4, 1900);
end; // insert_many_Click
|
Nous avons ajouté l'effacement dans la foulée. Pour effacer l'enregistrement
ayant le numéro 8, nous exécutons une requête
DELETE
FROM formations_3
WHERE f_numero= 8
|
En détail:
|
placez un tButton sur la Forme et créez sa méthode OnClick. Placez-y les
instructions de modification:
procedure TForm2.delete_all_Click(Sender: TObject);
begin
with IbSql1 do
begin
Close;
with Sql do
begin
Clear;
Add('DELETE FROM '+ k_table_name);
Add(' WHERE f_numero= 3');
end; // with Sql
Try
IbDatabase1.Open;
if ibtransaction1.InTransaction
then ibTransaction1.Commit;
ibtransaction1.StartTransaction;
ExecQuery;
ibtransaction1.Commit;
display(' ok');
except
on e: Exception do
display(' *** pb_create '+ e.Message);
end;
end; // with IbSql1
end; // delete_all_Click
|
|
|
compilez, exécutez, et cliquez le bouton
|
L'application en pleine action a l'allure suivante:
Vous pouvez télécharger les sources du projet "net_ibx_insert_data_3.zip.
Dans l'article Interbase Tutorial vous trouverez
aussi des exemple pour généraux pour ajouter des données en mode "batch".
Mentionnons que le projet m'a donné un peu de fil à retordre:
- j'étais parti du projet précédent (pour éviter la frappe des chemins divers)
- la sauvegarde du projet sous un nouveau nom s'est bien passée
- la sauvegarde de l'unité se fait apparemment dans son répertoire d'origine
(et non pas dans celui du .DPR sauvegardé auparavant)
- j'avais peut être aussi laissé traîner un autre projet
- et pour couronné le tout j'ai mal effacé le bouton "drop_table_". Il m'a
fallu un quart d'heure pour reprendre la main
- puis j'ai eu une succession de:
"object reference not set to an instance of an object"
A tout hasard, j'ai forcé les fermetures des requêtes avant de quitter
l'application, et cela se passait un peu mieux
- finalement j'ai fait deux ou trois erreurs dans mes requêtes SQL. Après
correction de l'erreur, fermeture de Delphi et rechargement du tout, le
problème disparaît. Cela me rappelle le temps de Delphi 1 et Windows 3.11.
On n'arrête pas le progrès
7 - Lire et Afficher
7.1 - 5.1- Principe
Pour afficher un enregistrement, nous devons d'abord récupérer ses valeurs du
Serveur.
Pour lire les données contenues dans une table, SQL utilise l'instruction
SELECT. Par exemple:
SELECT f_numero, f_nom
FROM formations_3
|
Lorsque le Serveur reçoit cette requête:
- il vérifie sa syntaxe
- il construit une table contenant les valeurs demandées
- ces données sont envoyées au Client
Plus concrètement:
Vous pouvez télécharger le source du projet "net_ibx_select.zip".
7.2 - Comment ça Marche
Lorsque nous exécutons IbQuery1.Open:
- Delphi envoie la requête SELECT au Serveur
- celui-ci construit une table résultat, en utilisant, bien sûr, la table
FORMATIONS, mais aussi éventuellement des tables annexes (index, contraintes
etc.).
- cette table résultat est envoyée via le réseau au Client Interbase. Celui
ci la transmet ensuite à l'application. Delphi place alors ce résultat dans
un tampon mémoire associé à tIbQuery:
7.3 - Affichage
Une fois que IbQuery a récupéré les données nous pouvons les afficher ou les
traiter en mémoire.
Pour afficher les données nous utilisons:
- un tDataSource qui récupère les données du tIbQuery
- un ou plusieurs composants d'affichage relié au tDataSource. Par exemple un
tDbGrid.
Par conséquent:
|
sélectionnez dans la page "Data Access" de la Palette le composant
tDataSource:
et placez le sur la Forme
|
|
sélectionnez dans la page "Data Controls" de la Palette le composant
tdbGrid:
et placez le sur la Forme
|
|
sélectionnez sa propriété DataSource et donnez-lui la valeur DataSource1
|
|
compilez, exécutez, et cliquez le bouton qui lance la requête
|
7.4 - Affichage en mode conception
Nous pouvons aussi lancer la requête de lecture en mode conception. Il faut
pour cela que:
- tIbDatabase soit correctement initialisé
- tIbQuery soit relié à tIbDatabase
- la propriété tIbQuery.Sql soit initialisée en utilisant l'Inspecteur
- la requête soit envoyée en basculant tIbQuery.Active sur True
Donc:
7.5 - SELECT
SELECT est la seule instruction de lecture de données du Serveur. Sa
structure générale est:
SELECT colonnes
FROM tables
WHERE conditions
|
et:
- colonnes indique quelles colonnes nous voulons voir figurer dans le
résultat. Nous pouvons
- citer explicitement les colonnes souhaitées, dans l'ordre qui nous
convient:
SELECT f_nom, f_numero
FROM formations
|
Nous pouvons ne demander qu'une partie des colonnes (projection)
SELECT f_nom
FROM formations
|
L'abréviation "*" permet de désigner "toutes les colonnes"
- effectuer des sommes, des moyennes (agrégats)
SELECT COUNT(*)
FROM formations
|
le résultat est alors une table d'une ligne, une colonne avec le nombre
de formations
- tables contient le noms des tables à utiliser pour calculer le résultat.
Par exemple:
SELECT *
FROM formations, dates
WHERE f_nom='UML ET DELPHI'
|
- conditions permet
- de ne retenir que certaines lignes du résultat. Par exemple
SELECT *
FROM dates
WHERE f_date> '2004/05/01'
|
- de trier le résultat:
SELECT *
FROM dates
ORDER BY f_date
|
Ce qu'il faut bien comprendre est que:
- SELECT calcule un résultat A PARTIR de tables, mais que le résultat
n'EST PAS les tables. Lorsque nous demandons une somme ou une moyenne, par
exemple, SELECT retourne un nombre.
- Certes, "SELECT * FROM formations" retourne bien les mêmes
données que celle de la table sur disque "formations". Mais ce n'est qu'un
instantané réalisé lorsque la requête a été lancée. Il s'agit d'une copie.
Si un autre utilisateur ajoute une nouvelle formation la copie que nous
avons dans le cache attaché à IbQuery ne le reflète pas
- pour rafraîchir notre cache, la SEULE façon de faire est de relancer la
requête (en fermant et réouvrant tIbQuery)
8 - Modifier des Données
8.1 - Principe
Supposons que notre table FORMATIONS contienne les valeurs suivantes:
Pour changer le libellé "Interbase Delphi" en "Interbase" nous utilisons une
requête UPDATE:
UPDATE formations
SET f_nom= 'Interbase'
WHERE f_numero= 8
|
Cette requête qui modifie les données du Serveur est envoyée vers le Serveur
en utilisant tIbSql1.ExecQuery out tIbQuery1.ExecSql
En détail:
Vous pouvez télécharge le source du projet "net_ibx_update.zip".
8.2 - La clause WHERE
Dans l'instruction précédente nous avons spécifié la valeur f_numero à l'aide
de WHERE.
Que se passerait-il si nous envoyons:
UPDATE formations
SET f_nom= 'Interbase'
|
Eh bien le Serveur modifierait le nom de TOUS les enregistrements.
Si nous souhaitons limiter les modifications à certaines lignes, il est
impératif:
- que chaque ligne de chaque table ait un identificateur unique pour que nous
puissions désigner cette ligne en cas de modification
- que nous indiquions dans UPDATE les lignes à modifier
Si en revanche nous souhaitons modifier plusieurs lignes à la fois, nous
pouvons :
- omettre WHERE. Par exemple, pour passer tous les noms en majuscule:
UPDATE formations
SET f_nom= UPPER(f_nom)
|
- changer plusieurs lignes satisfaisant une condition. Pour effectuer une
réduction promotionnelle de 5% sur les prix inférieurs à 1400 euros :
UPDATE formations
SET f_prix= f_prix* 0.95
WHERE WHERE f_prix<= 1400.00
|
Toutefois:
- ne répétez pas cette requête de réduction trop souvent: il faut bien que
je mange un peu !
- nous faisons des conditions tarifaires particulières (groupes, formations
intra, étudiant, particulier, réinsertion...), que nous sommes prêts à
vous présenter si vous me téléphonez directement à l'Institut Pascal au
01.42.83.69.36.
Il est donc fondamental de bien comprendre qu'un UPDATE sans clause
WHERE porte sur tous les enregistrements.
8.3 - UPDATE et AFFICHAGE
Ce fonctionnement de UPDATE est particulièrement important lorsque nous
modifions un enregistrement affiché à l'écran dans un dbGrid: nous pensons que
Interbase sait que nous "modifions l'enregistrement courant". Or ce concept
d'enregistrement courant n'existe pas en mode SQL:
La seule façon de modifier une valeur affichée de façon interactive est de
déclencher une requête UPDATE en utilisant un composant tIbUpdateSql. Le
plus simple pour synchroniser les modifications est d'utiliser un composant
tIbUpdateSql.
8.4 - tIbUpdateSql
Ce composant a pour vocation de contenir la requête SQL qui doit être exécutée
lorsque le tIbQuery doit être modifié. Cette requête est placée dans
tIbUpdateSql.ModifySql.
Automatisons par exemple la mise à jour de f_nom lorsque nous tapons une
valeur dans un tDbGrid:
|
créez une nouvelle application et appelez-la "p_net_ibx_update_sql"
|
|
placez un tIbTransaction sur la Forme
|
|
placez un tIbDataBase sur la Forme. Cliquez deux fois sur IbDataBase1,
renseignez "local", "DataBase", "User Name" "Pass Word" et "Login Prompt".
Vérifiez la connection en basculant IbDataBase1.Connected sur True, puis
fermez la connection.
Sélectionnez DefaultTransaction et initialisez-la à IbTransaction1
|
|
placez un tIbQuery sur la tForme
- sélectionnez sa propriété DataBaseName et initialisez-la à IbDataBase1
- sélectionnez sa propriété Sql et placez-y la requête
Vous pouvez aussi utiliser l'Editeur de Requête en cliquant sur l'ellipse
... de Sql:
|
|
ajoutez un composant tDataSource
- sélectionnez DataSet et donnez-lui la valeur IbQuery1
|
|
reliez DataSource1 à un tDbGrid:
- placez un tdbGrid de sur la Forme
- sélectionnez sa propriété DataSource et reliez la à DataSource1
|
|
ouvrez IbQuery1 en basculant Active sur True
|
|
ajoutez un tIbUpdateSql:
- sélectionnez la page "Interbase" de la Palette, sélectionnez le
composant tIbUpdateSql et posez-le sur la Forme
- connectez le IbQuery1 et IbUpdateSql:
- en initialisant IbQuery1.UpdateObject avec IbUpdateSql1
- en basculant IbQuery1.CachedUpdate à True
- sélectionnez sa propriété IbUpdateSql1.ModifySql, cliquez sur
l'ellipse pour ouvrir l'éditeur de ModifySql (c'est un éditeur de
tStrings). Delphi y a placé la requête par défaut:

|
|
compilez, exécutez:
- Sélectionnez dbGrid1, tapez une valeur dans la colonne F_NOM.
- Notez bien que le dbGrid permet à présent la modification de valeurs
(alors que sans tIbUpdateSql ces modifications étaient impossibles).
- lorsque nous quittons la ligne (en changeant de composant, ou en
changeant de ligne dans le dbGrid), la requête de modification est
envoyée vers le Serveur
|
Notez que:
Vous pouvez télécharger le projet "net_ibx_update_sql.zip".
8.5 - "Old" values
Nous avons utilisé f_numero pour identifier la ligne à modifier. Mais que se
passe-t-il si nous souhaitons modifier la clé elle-même ? En effet :f_numero
désigne la valeur actuelle, qui est la valeur modifiée, et non pas la valeur
qui permet de désigner la ligne dans la table.
Pour résoudre ce problème, Delphi a crée le concept des "old_values",
correspondant à la valeur que le champ avait lors de la lecture de la table. Et
le paramètre pour désigner la valeur se note :old_f_numero
Si nous souhaitons pouvoir modifier tous les enregistrements, nous utilisons
donc dans tIbUpdateSql.ModifySql une requête du type:
UPDATE formations
SET f_numero= :f_numero, f_nom= :f_nom
WHERE f_numero= :old_f_numero
|
Ce concept de "old values" est fondamental pour la mise à jour concurrente que
nous présenterons voir ci-dessous.
9 - Télécharger les Exemples
Voici les programmes utilisés dans cet article et que vous pouvez télécharger:
Les .ZIP comprennent:
- le .DPR, la forme principale, les formes annexes eventuelles
- les fichiers de paramètres (le schéma et le batch de création)
- dans chaque .ZIP, toutes les librairies nécessaires à chaque projet (chaque
.ZIP est autonaume)
Ces .ZIP contiennent des chemins RELATIFS. Par conséquent:
- créez un répertoire n'importe où sur votre machine
- placez le .ZIP dans ce répertoire
- dézippez et les sous-répertoires nécessaires seront créés
- compilez et exécutez
Ces .ZIP ne modifient pas votre PC (pas de changement de la Base de Registre,
de DLL ou autre). Pour supprimer le projet, effacez le répertoire.
Comme d'habitude:
- nous vous remercions de nous signaler toute erreur, inexactitude ou
problème de téléchargement en envoyant un e-mail à jcolibri@jcolibri.com. Les corrections
qui en résulteront pourront aider les prochains lecteurs
- tous vos commentaires, remarques, questions, critiques, suggestion
d'article, ou mentions d'autres sources sur le même sujet seront de même
les bienvenus à jcolibri@jcolibri.com.
- plus simplement, vous pouvez taper (anonymement ou en fournissant votre
e-mail pour une réponse) vos commentaires ci-dessus et nous les envoyer en
cliquant "envoyer" :
- et si vous avez apprécié cet article, faites connaître notre site,
ajoutez un lien dans vos listes de liens ou citez-nous dans vos réponses
sur les messageries. C'est très simple: plus nous aurons de visiteurs et de
références Google, plus nous écrirons d'articles.
10 - Conclusion
Lors de cette présentation de dbExpress, nous avons indiqué comment installer
Interbase, créer une base, des tables, ajouter, lire, modifier et effacer des
données.
Si vous avez des questions, vous pouvez:
- vous reporter au livre Delphi dBase qui
présente, par le détail, la gestion des composants visuels et les techniques
de traitement des données (formatage, vérfications, calculs...)
- pour les blobs, voyez Blobs Interbase
- pour l'utilisation d'Interbase en mode Client Serveur, sans utiliser le
BDE, voyez le Tutorial Interbase
- la présentation Architecture du Moteur
Interbase présente l'organisation du programme Interbase, correspondant
aux sources fournies par Borland pour la version 6.
- je présenterai à la conférence Borcon France 2004 le
panorama des techniques d'accès aux données Interbase: les API isc, le
BDE, Interbase Express, dbExpress, et pour Delphi 8, IBX.NET en mode
VCL.NET et ADO.NET en mode Windows Forms.
- vous pouvez aussi m'adresser vos questions par e-mail à jcolibri@jcolibri.com
Nous n'avons pas essayé d'être exhaustif dans la présentation. Lors des stages
que j'anime personnellement à l'Institut Pascal, j'entre beaucoup plus dans le
détail:
- la gestion des multiples erreurs et exceptions qui interviennent lors
d'applications utilisant des bases de données
- les possibilités d'installer Interbase depuis Delphi, et d'interroger les
paramètres de la Base ou du schéma depuis un programme Delphi, de lister
les tables, les champs etc
- le traitement des contraintes (clé primaires, intégrité référentielle,
intégrité sémantique)
- la manipulation détaillée des valeurs extraite d'une Table, en utilisant les
tFields et les différents composants visuels tDb_xxx, ainsi que les
traitements spécifiques aux chaînes, aux dates, aux blobs
- les techniques de validation de saisie essentielles pour toute application
de gestion
- le traitement spécifiques à dbExpress:
- l'utilisation de tClientDataset avec ses multiples possibilités
- les paramétrage du tDatasetProvider
- la gestion des erreurs de réconciliation et le traitement d'utilisateurs
multiples
- l'étude approfondie du langage SQL, qui est au coeur de tout traitement avec
des Serveurs Sql
- les triggers, les procédures cataloguées (tStoredProc), les générateurs
- la gestion de Serveur (sauvegarde / restauration, statistiques, réglage)
Pour examiner le programme détaillé de cette formation, cliquez
Client Serveur Interbase. Nous
proposons de plus d'autres formations présentées dans ces
pages (programme, dates des prochaines sessions,
conditions, transparents, abonnement à la lettre
d'information...).
Finalement j'interviens aussi pour des missions d'audit, de réalisation de
projet, de portage et maintenance, et de tutorat.
11 - L'auteur
John COLIBRI est passionné par le développement
Delphi et les applications de Bases de Données. Il a écrit de nombreux livres
et articles, et partage son temps entre la
développement de projets pour
ses clients, le conseil et la formation. Son site contient des articles
avec code source, ainsi que le programme et le calendrier des
stages
de formation Delphi, base de données, Ado.Net, Asp.Net et UML qu'il
anime personellement tous les mois, à Paris, en province ou sur site client.
|