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 blogs ou 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 le développement de projets (nouveaux projets, maintenance, audit, migration BDE, migration Xe_n,
refactoring) pour ses clients, le conseil (composants, architecture, test) 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, programmation objet, Services Web, Tcp/Ip et
UML qu'il anime personellement tous les mois, à Paris, en province ou sur site client. |