|
Interbase dbExpress - John COLIBRI.
|
- mots clé:tutorial - Interbase - dbExpress - DataSnap - Midas
- logiciel utilisé: Windows XP, Delphi 6, Interbase 6
- matériel utilisé: Pentium 1.400Mhz, 256 M de mémoire
- champ d'application: Delphi 1 à 8 sur Windows, Kylix
- 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 dbExpress. Ce tutorial a plusieurs objectifs:
- vous présenter intégralement comment réaliser des applications utilisant des
bases de données Sql en Delphi. 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 avons présenté dans le tutorial interbase
comment utiliser des bases de données en mode Client Serveur. Dans cet
article, nous nous concentrons sur le mode dbExpress. Les deux articles
peuvent être lus indépendemment l'un de l'autre. Si vous avez lu le tutorial
Client Serveur auparavant, les paragraphes sur l'installation d'Interbase,
et le fonctionnement de SQL en tant que langage sont similaires, et vous pouvez
les sauter: la partie spécifique à dbExpress commence à partir de la création
de la table.
Pour l'utilisaton d'Interbase avec Delphi 8 et le .Net Framework, vous
pouvez consulter les articles suivants:
- 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. Contient aussi un comparatif
de toutes ces architectures avec les schémas correspondants
- 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
Mentionnons qu'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 ce premier contact vous souhaitez approfondir vos connaissances, nous
vous proposons soit des formations ou des prestations de
programmation et d'assistance.
Nous nous adressons pour ce tutorial à un programmeur Delphi:
- ayant une idée élémentaire de Delphi: Palette, Inspecteur, OnClick. Tout
le reste sera expliqué
- n'ayant pas nécessairement de connaissance SQL. Le fonctionnement des
requêtes et leur syntaxe sera présenté
2 - Installation
2.1 - Principe
Le logiciel Interbase comporte essentiellement deux parties:
- le programme Serveur (le moteur), qui en général est placé sur un PC
distant
- le programme Client, qui dialogue avec les programme applicatifs (Delphi
ou autre).
Il faut donc installer les deux parties (sur la même machine ou sur des PC
séparés).
Interbase peut fonctionner selon deux modes:
- le mode dit "local", pour lequel le moteur et le programme client sont sur
le même PC. La machine n'a pas besoin d'avoir les couches réseau (TCP\IP,
Novell ou autre), ni de carte réseau (carte Ethernet ou liaison série). Le
programme applicatif communique avec le Client, qui appelle directement les
routines du serveur (sans passer par des appels TCP\IP)
- le mode Client Serveur
- les communications entre la DLL client et le Serveur passent par les
couches réseau de Windows: il faut que ces couches réseau soient
installées (même si le Serveur et le Client sont sur le même PC)
- le programme applicatif devra désigner le serveur en utilisant l'adresse
IP du serveur.
Dans les deux cas, l'installation se fait en utilisant l'installateur du CD
Delphi (ou du CD Interbase). Nous présenterons l'installation à partir du CD
Delphi.
2.2 - Installation avec Delphi
Lors de l'installation de Delphi, Installshield propose d'installer aussi
Interbase.
Vous pouvez répondre oui et Interbase sera installé
Si vous avez répondu "Non", voici comment procéder:
2.3 - Installation du Mode Local
Pour installer Interbase en mode local:
2.4 - Installation du Mode Distant
Installez le Serveur sur le PC serveur, en procédant comme ci-dessus, mais
sélectionnez "Interbase 6 Server". La partie Client installée sur le PC du
Serveur sera utilisée pour les logiciels de gestion du Serveur
Installez le Client sur le PC client:
2.5 - Suppression d'Interbase
Pour supprimer Interbase:
|
ouvrez le Serveur Manager et cliquez "Stop" (pour arrêter le moteur)
|
|
ouvrez le panneau de configuration, sélectionnez "Ajout / Suppression de
logiciel", sélectionnez "Interbase" et cliquez Oui partout
|
3 - Créer la Base
3.1 - SQL et la création de bases
Pour créer une base, il faut, pour tous les moteurs, utiliser des outils
spéciaux, le langage SQL ne contenant pas de requête spécifique pour cette
opération
Pour Interbase, ce sont des primitives de l'API native du moteur qui permettent
cette création. Elle n'est pas possible depuis les composants générique d'accès
aux données (tTable, tQuery). En revanche, Jeff Overcash a ajouté à
tIbDatabase la méthode qui utilise les API Interbase natifs et permet la
création de la base.
Les éléments à fournir sont les suivants;
- le chemin DOS où sera placé le fichier .GDB
- le dialecte Interbase à utiliser. En gros, le dialecte détermine le
traitement de certains types de données Interbase (en dialecte 3 nous
pouvons utiliser des Integer 64 bits et des tTimeStamps, minuscule ou
majuscule sont reconnus etc). Nous choisirons le dialecte 3 (le plus
récent).
- le nom d'utilisateur et le mot de passe du Serveur. Ce sont les noms du
serveur par défaut (la base n'étant pas encore créée, elle)
- des paramètres d'optimisation, tels que la taille des pages du cache
Plus précisément:
- le chemin est placé dans tIbDatabase.DataBaseName
- le dialecte est placé dans tIbDatabase.SqlDialect
- le nom d'utilisateur et le mot de passe, ainsi que les autres paramètres
sont placés dans la propriété fourre-tout Params
- la méthode de création est simplement:
tIbDatabase.CreateDataBase
|
3.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_ib_create_base"
|
|
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
et placez-la sur la tForm
|
|
initialisez IbDatabase.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 TForm1.create_database_Click(Sender: TObject);
begin
with IbDatabase1 do
begin
DatabaseName:= '..\data\Institut_Pascal.gdb';
SqlDialect:= 3;
Params.Add('USER "SYSDBA"');
Params.Add('PASSWORD "masterkey"');
Params.Add('PAGE_SIZE 4096');
CreateDatabase;
end; // with IbDataBase1
end; // create_database_Click
|
|
|
compilez et exécutez
|
|
cliquez Button1
|
|
le répertoire ..\data\ contient bien le fichier "Institut_Pascal.GDB"
dont la taille est d'environ 580 K
|
Notez que:
- si le fichier formation.gdb existait déjà il faut tester sa présence
(FileExists) et l'effacer (Erase)
- si nous souhaitons répéter la création, il faudrait purger les Params avant
tout ajout par Add (Params.Clear)
Vous pouvez télécharger ce projet "ib_dbx_create_base.zip".
Maintenant que notre base est créée, nous allons utiliser les composants
dbExpress pour accéder aux données de notre base. Si vous souhaitez continuer
à utiliser les composants IbDatabase, IbQuery etc, consultez
le tutorial Interbase en mode Client Serveur.
4 - Connection à une base
Pour nous connecter à une base Interbase nous allons utiliser un composant
SqlConnection.
Ce composant doit être initialisé avec:
- dans DriverName, le nom du pilote Interbase:
Interbase
- dans ConnectionName le nom de la connexion:
IbLocal
- dans Params les paramètres propres à Interbase, tels que le nom
d'utilisateur, le mot de passe, le chemin où se trouve le fichier .GDB etc
Pour spécifier l'endroit où se trouve le fichier .GDB, nous fournissons:
- soit le chemin, si nous travaillons en local:
c:\programs\interbase\data\Institut_Pascal.gdb
ou
..\data\Institut_Pascal.gdb
- soit l'URL du PC qui héberge le Serveur:
127.0.0.1\ c:\programs\interbase\data\Institut_Pascal.gdb
HostName\ c:\programs\interbase\data\Institut_Pascal.gdb
www.jcolibri.com\
c:\programs\interbase\data\Institut_Pascal.gdb
Pour initialiser tous ces paramètres, nous employons l'éditeur de
tSqlConnection:
Notez que:
- lorsque nous avons créé la base, nous avons choisi le "dialecte 3". C'est la
version Sql du moteur
- lorsque nous connectons la base, nous avons choisi le "dialecte 3": c'est le
dialecte du client Interbase.
- 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. En fait, chaque accès à Interbase ouvrira automatiquement la
connexion. Nous pouvons donc:
- soit laisse dbExpress ouvrir automatiquement la connexion
- soit ouvrir la connexion lors de l'exécution en appelant;
tSqlConnection.Connected:= True;
Nous allons donc fermer la connexion en mode conception:
|
sélectionnez SqlConnection1, sélectionnez dans l'Inspecteur d'Objet
la propriété Connected et basculez sa valeur sur False
|
5 - Créer une Table
5.1 - Principe
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
(f_numero INTEGER, f_nom CHARACTER(11), 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 tSqlConnection qui assurera la connection vers le
Serveur
- nous utilisons un tSqlQuery
- nous le relions à tSqlConnection
- nous plaçons la requête SQL dans sa propriété ISqlQuery.SQL (via
l'Inspecteur ou en code)
- nous appelons tSqlQuery.ExecSql
5.2 - Utilisation de SQL
La requête à envoyer au Serveur est placée dans tSqlQuery.Sql.
tSqlQuery.Sql est un descendant de tStrings. Nous pouvons donc utiliser, par
exemple:
SqlQuery1.Sql.Add('CREATE TABLE formations (f_numero INTEGER, f_nom CHARACTER(11))');
|
Pour construire la requête:
- nous pouvons utiliser Add pour ajouter une ligne de requête, Text pour
affecter une requête, Clear pour purger tout texte antérieur, ou même
LoadFromFile pour lire un fichier .txt contenant la requête:
SqlQuery1.Sql.LoadFromFile('cree_formation.txt');
|
La mise en page n'a aucune importance pour le Serveur: la requête peut être
répartie en plusieurs lignes:
SqlQuery1.Sql.Add('CREATE TABLE');
SqlQuery1.Sql.Add(' formations ');
SqlQuery1.Sql.Add(' (f_numero INTEGER, f_nom CHARACTER(11))');
|
l_requete:= 'CREATE TABLE '+ Edit1.Text+ ' (';
l_requete:= l_requete+ Edit2.Text+ ')';
SqlQuery1.Sql.Add(l_requete);
|
5.3 - Comment ça Marche
Au niveau fonctionnement:
Notez que l'envoi de toute requête qui modifie des données du Serveur (et la
création d'une nouvelle table est bien une modification) ne peut se faire que
par du code (PAS en basculant SqlQuery1.Active sur True en mode conception)
5.4 - L'application
Pour créer notre table
|
créez une nouvelle application et appelez-la "ib_dbx_create_table"
|
|
sélectionnez dans la page "dbExpress" de la Palette le composant
SqlConnection:
et posez-le sur la tForm
|
|
Cliquez deux fois sur SqlConnection1, renseignez "Driver Name",
"Connection Name", "DataBase", "Dialect", "User Name" et "Pass Word"
Sélectionnez la propriété LoginPrompt et basculez sa valeur sur False
Vérifiez la connection en basculant SqlConnection1.Connected sur True,
puis fermez la connection (pour éviter de monopoliser un utilisateur). La
connection sera ouverte avant l'envoi de la requête
|
|
sélectionnez dans la page "dbExpress" de la Palette le composant
SqlQuery:
|
|
sélectionnez sa propriété SqlConnection et initialisez-la à
SqlConnection1
|
|
placez un tButton sur la Forme et créez sa méthode OnClick. Placez-y les
instructions de création:
|
procedure TForm1.create_table_Click(Sender: TObject);
begin
with SqlQuery1 do
begin
Close;
with Sql do
begin
Clear;
Add('CREATE TABLE formations');
Add(' ('
+' f_numero INTEGER,');
Add(' f_nom CHAR(23),');
Add(' f_jours SMALLINT,');
Add(' f_prix NUMERIC(5, 2)');
Add(' )');
end; // with Sql
Try
ExecSql;
except
on e: Exception do
begin
display(' *** pb_create '+ e.Message);
end;
end;
end; // with SqlQuery1
end; // create_table_Click
|
|
compilez, exécutez, et cliquez le bouton
|
Vous pouvez télécharger le sources du projet "ib_dbx_create_table.zip".
5.5 - 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
au moteur. Nous verrons cette requête SELECT en
détail plus bas, mais voici comment procéder pour notre test:
|
placez un second tButton sur la Forme et placez-y la requête de lecture:
|
procedure TForm1.select_Click(Sender: TObject);
begin
with SQLQuery1 do
begin
Close;
with Sql do
begin
Clear;
Add('SELECT * FROM formations');
Try
Open;
display(' ok');
except
on e: Exception do
display(' *** pb '+ e.Message);
end;
end; // with Sql
end; // with SQLQuery1
end; // select_Click
|
|
compilez, exécutez, et cliquez le bouton
|
5.6 - 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 TForm1.drop_table_Click(Sender: TObject);
begin
with SQLQuery1 do
begin
Close;
with Sql do
begin
Clear;
Add('DROP TABLE formations');
Try
ExecSql;
display(' ok');
except
on e: Exception do
display(' *** pb '+ e.Message);
end;
end; // with Sql
end; // with SQLQuery1
end; // drop_table_Click
|
|
compilez, exécutez, et cliquez le bouton
|
Notez que:
- nous avons le même SqlQuery en changeant le contenu de sa propriété SQL.
Nous aurions aussi bien pu utiliser 3 SqlQuery séparés.
- notez que pour envoyer une requête de modification il faut utiliser
tSqlQuery.ExecSql, alors que pour lire les données nous utilisons
tSqlQuery.Open.
tSqlQuery.Open est équivalent à tSqlQuery1.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)
5.7 - Les Transactions
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 actions 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.
Si nous utilisons InterbaseExpress (IBX, qui est le jeu de composants utilisés
dans l'article Interbase Tutorial ), il faut
systématiquement placer un composant IbTransaction sur la tForm. C'est
d'ailleurs ce que nous avons effectué pour la création de la base au début de
cet article.
Si nous utilisons dbExpress, c'est Delphi qui se charge de gérer les
transactions de façon transparente. Nous n'avons donc pas utilisé de composant
transaction pour créer notre table.
Nous pouvons cependant le faire si nous souhaitons regrouper plusieurs actions.
Voici un exemple de suppression de Table utilisant une transaction explicite:
procedure TForm1.drop_with_transaction_Click(Sender: TObject);
var l_transaction_descriptor: TTransactionDesc;
begin
with SQLQuery1 do
begin
Close;
with Sql do
begin
Clear;
Add('DROP TABLE formations');
if not SQLConnection1.InTransaction
then begin
l_transaction_descriptor.TransactionID:= 1;
l_transaction_descriptor.IsolationLevel:= xilREADCOMMITTED;
SQLConnection1.StartTransaction(l_transaction_descriptor);
Try
ExecSql;
SQLConnection1.Commit(l_transaction_descriptor);
display(' ok');
except
on e: Exception do
begin
display(' *** pb '+ e.Message);
SQLConnection1.Rollback(l_transaction_descriptor);
end;
end;
end
else display('already_in_transaction');
end; // with Sql
end; // with SQLQuery1
end; // drop_with_transaction_Click
|
5.8 - Automatisation de la création de Table
Si nous avons plusieurs tables à créer, le codage en dur se révèle très vite
fastidieux. Or il est très simple de paramétrer une procédure générique, et
d'appeler cette procédure en lisant les paramètres depuis un fichier.
Une solution est de placer sur disque les requêtes SQL et de lire et exécuter
ces requêtes les unes après les autres.
Nous avons préféré utiliser une définition plus schématique qui est analysée
par la procédure de lecture.
Voici notre schéma que nous avons tapé dans NotePad et placé dans le fichier
"schema_simple.txt":
formations
f_numero INTEGER
f_nom CHAR(23)
f_jours INTEGER
f_prix NUMERIC(9, 2)
dates
d_formation INTEGER
d_date TIMESTAMP
d_ville INTEGER
villes
v_numero INTEGER
v_nom CHAR(30)
|
Nous avons simplement fourni
- le nom de chaque table, à la marge
- le nom des champs et leur type Interbase, indenté de deux espaces
On peut difficilement faire plus simple !
Notre programme va alors
- lire le fichier
- générer la requête pour créer chaque table
Et:
- la création de la table est réalisée par une classe dont voici la
définition:
USES ... , SqlExpr;
type c_create_ib_table= class(c_basic_object)
m_table_name: String;
m_c_ib_dbx_query_ref: tSqlQuery;
m_c_fields: tStringList;
m_exec_sql: Boolean;
Constructor create_ib_table(p_name, p_table_name: String;
p_c_ib_query: tSqlQuery);
procedure drop_table;
procedure create_table;
procedure display_sql;
Destructor Destroy; Override;
end; // c_create_ib_table
|
- la méthode de création de la table est la suivante:
procedure c_create_ib_table.create_table;
var l_field_index: Integer;
begin
drop_table;
with m_c_ib_dbx_query_ref, Sql do
begin
Clear;
Add('CREATE TABLE '+ m_table_name+ ' (');
for l_field_index:= 0 to m_c_fields.Count- 2 do
Add(m_c_fields[l_field_index]+ ',');
Add(m_c_fields[m_c_fields.Count- 1]+ ' )');
if m_exec_sql
then
try
ExecSql;
display(' ok '+ m_table_name);
except
on e: Exception do
display(' *** pb_create '+ e.Message);
end // try ... Except
else display('did_not_ask_to_create');
end; // with m_c_ib_dbx_query_ref, Sql
end; // create_table
|
- cette méthode utilise la liste de définition des champs qui est chargée à
partir du fichier par la procédure suivante
procedure TForm1.create_script_Click(Sender: TObject);
const k_exec_sql= [0, 1, 2];
var l_list_index: Integer;
l_line, l_trimmed_line: String;
l_c_create_ib_table: c_create_ib_table;
l_table_index: Integer;
begin
with tStringList.Create do
begin
LoadFromFile(k_script_path+ k_script_name);
l_c_create_ib_table:= Nil;
l_table_index:= 0;
for l_list_index:= 0 to Count- 1 do
begin
l_line:= Strings[l_list_index];
l_trimmed_line:= Trim(l_line);
if l_trimmed_line<> ''
then begin
if l_trimmed_line= l_line
then begin
if Assigned(l_c_create_ib_table)
then begin
l_c_create_ib_table.create_table;
l_c_create_ib_table.Free;
Inc(l_table_index);
end;
l_c_create_ib_table:= c_create_ib_table.create_ib_table('', l_line, SqlQuery1);
l_c_create_ib_table.m_exec_sql:= l_table_index in k_exec_sql;
end
else begin
l_c_create_ib_table.m_c_fields.Add(l_trimmed_line);
end;
end;
end; // for l_list_index
if Assigned(l_c_create_ib_table)
then begin
l_c_create_ib_table.create_table;
l_c_create_ib_table.Free;
end;
Free;
end; // with tStringList
end; // create_script_Click
|
Notez que:
- la procédure c_create_ib_table.create_table commence par appeler la
procédure c_create_ib_table.drop_table. Pour la première création, ceci
est inutile, mais si vous créez une seconde fois la base, il faut d'abord
effacer la table, sinon le Serveur refuse la création.
- mais dans le cas de la première création, DROP TABLE provoque aussi une
exception. C'est pourquoi cette instruction est placée dans un
TRY ... EXCEPT. Cette exception va interrompre l'exécution. Pour
poursuivre la création:
- vous pouvez taper F9 pour passer outre
- vous pouvez placer Delphi en mode "ne pas s'arrêter en cas d'exceptions"
en suprimant la coche de la CheckBox "stop on Delphi Exceptions" située
dans:
Tools | Debugger | Language Exceptions
C'est le mode préféré lorsque l'on utilise beaucoup de bases de données,
compte tenu des nombreuses exceptions provoquées à tous les niveaux (Serveur
Sql, pilote, BDE ou dBExpress, Ibx etc).
Vous pouvez télécharger le source du projet
"ib_dbx_create_tables_with_script.zip".
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
(f_numero, f_nom)
VALUES (3, 'Interbase Delphi')
|
L'ajout d'enregistrement va modifier les données du Serveur, donc nous
utiliserons tSqlQuery.ExecSql.
De façon détaillée:
|
créez une nouvelle application et nommez-la "ib_dbx_insert_data"
|
|
placez un tSqlConnection sur la Forme. Cliquez deux fois sur
SqlConnection1, renseignez "Driver Name", "Connection Name", "DataBase",
"Dialect", "User Name" et "Pass Word".
Basculez LoginPrompt sur False, et vérifiez la connection en basculant
SqlConnection1.Connected sur True, puis fermez la connection.
|
|
placez un tSqlQuery sur la tForme
|
|
sélectionnez sa propriété SqlConnection et initialisez-la à
SqlConnection1
|
|
placez un tButton sur la Forme et créez sa méthode OnClick. Placez-y les
instructions d'ajout:
procedure TForm1.insert_Click(Sender: TObject);
begin
with SqlQuery1 do
begin
Close;
with Sql do
begin
Clear;
Add('INSERT INTO formations');
Add(' (f_numero, f_nom)');
Add(' VALUES (3, ''Delphi Iterbase'')');
end;
Try
ExecSql;
display(' ok');
except
on e: Exception do
display(' *** pb_insert '+ e.Message);
end;
end; // with SqlQuery1
end; // insert_Click
|
|
|
compilez, exécutez, et cliquez le bouton
|
Vous pouvez télécharger les sources du projet "ib_dbx_insert_data.zip".
6.2 - Type CHARACTER
Pour spécifier les valeurs CHARACTER, Sql exige que la chaîne soit
entourée de guillemets. Suivant les Serveurs, il faut utiliser un guillemet
simple ou double:
|
VALUES (3, 'Interbase Delphi')
|
ou
|
VALUES (3, "Interbase Delphi")
|
De plus si notre valeur est nichée dans une String Pascal, il faut dédoubler
les guillemets
IbQuery1.Sql.Add(' VALUES (3, ''Interbase Delphi'')');
|
Pour simplifier cet imbroglio de guillemets, Delphi propose la méthode
QuotedStr:
IbQuery1.Sql.Add(' VALUES (3, '+ QuotedStr('Interbase')+ ')');
|
6.3 - Type NUMERIC
Pour les valeurs numériques avec décimales, nous devons batailler avec les
points et les virgules:
La règle est donc simple:
- les valeurs Delphi (Double ou autre) utilisent le point '.'
- les composants visuels (tEdit etc) et les primitives de conversion
(FloatToStr) utilisent la virgule ','
6.4 - Type DATE
Un problème similaire intervient pour les dates:
En supposant que nous souhaitions fournir la date du 29 Mars 2004, nous pouvons
utiliser:
INSERT INTO dates
(d_numero, d_date)
VALUES (3, '2004/03/29')
|
et:
IbQuery1.Sql.Add('INSERT INTO dates');
IbQuery1.Sql.Add(' (d_numero, d_date');
IbQuery1.Sql.Add(' VALUES (3, ''2004/03/29'')');
|
6.5 - Automatisation de l'Ajout
Les valeurs à insérer ont été figées dans notre code. Nous pouvons automatiser
cet ajout
- soit par des scripts
- soit par une procédure amplement paramétrée
- soit en mode interactif.
Nous allons présenter ici l'utilisation d'une procédure.
En fait il n'y a rien de nouveau par rapport à la technique ci-dessus, sauf que
- la chaîne de la requête est construite en fonction de paramètres de la
procédure
- la procédure appelante envoie les paramètres requis
Voici un exemple de procédure générique d'ajout:
procedure insert_generic(p_number: Integer; p_name: String; p_days: Integer; p_cost: Double);
begin
with Form1, SqlQuery1 do
begin
Close;
with Sql do
begin
Clear;
Add('INSERT INTO formations');
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;
Try
ExecSql;
display(' ok');
except
on e: Exception do
display(' *** pb_insert '+ e.Message);
end;
end; // with SqlQuery1
end; // insert_generic
|
Et voici un exemple de procédure appelante
procedure TForm1.insert_batch_Click(Sender: TObject);
begin
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 Delphi', 3, 1400);
insert_generic(4, 'Initiation Pascal', 4, 1900);
end; // insert_automatic_Click
|
Notez que:
- la procédure appelante pourrait aussi bien lire ses donnée d'une autre
source (un fichier FILE OF, un fichier ASCII ("comma separates values" ou
autre), un autre table (Oracle, Sql Serveur ou même une autre table
Interbase...)
- le paramètres p_cost est de type Double:
- la procédure appelante envoie une valeur littérale avec un point décimal
insert_generic(2, 'Bases de Données Delphi', 3, 1.400);
|
- la procédure appelée utilise FloatToStr, qui attend une virgule
décimale. Nous forçons donc temporairement l'utilisation du point:
DecimalSeparator:= '.';
Add(' VALUES ('+ IntToStr(p_number)+ ... + FloatToStr(p_cost)+ ')');
DecimalSeparator:= ',';
|
Pour vérifier que nos ajouts ont effectivement réussi, nous avons ajouté à
notre application trois boutons qui ouvrent chaque table et comptent simplement
le nombre de fiches. Le véritable affichage du contenu de chaque ligne nous
allons le réaliser maintenant, et en utilisant un tClientDataSet.
7 - Lire et Afficher
7.1 - Principe de dbExpress
Le lecteur ayant lu le Tutorial Interbase aura
constaté que tous les traitements précédents sont quasiment identiques à ceux
que nous avions effectués en utilisant les composants IBX:
- SqlConnection a remplacé IbDatabase
- SqlQuery a remplacé IbSql
- les transactions sont gérées automatiquement par dbExpress, au lieu
d'utiliser un ibTransaction explicite
Les choses vont réellement changer avec les composants de lecture. Pour mettre
en perspective les différences de traitement, nous allons évoquer succintement
les architectures possibles.
7.2 - Le mode Sql pur
Si nous utilisons les API Interbase, nous avons fondamentalement deux types
d'instructions Sql:
- les instructions qui modifient les données (création de table, écriture de
données, modifications, effacement...)
- les instructions qui lisent les données. Le Serveur contient des Tables
dont le Client souhaite récupérer des données:
Le programmeur:
- prépare un tampon de réception
- envoie la requête "SELECT ..." vers le serveur
- le Serveur crée une table correspondant à cette requête:
- le Serveur envoie les enregistrements demandés par paquets vers le
Client qui les dépose dans la mémoire qu'il avait préparée:
Rien ne relie les données reçues à des modifications de ces données.
7.3 - Le BDE
Le moteur de base de données Borland (Borland Database Engine) utilise
les API, mais les données lues par SELECT sont stockées dans un cache du BDE.
Le Client:
- associe un tTable à une Table du Serveur
- lorsque le Client ouvre la Table, le BDE envoie une requête SELECT vers le
Serveur
- les données recueillies sont stockées dans des caches gérés par le BDE
- le Client récupère ces données pour les traiter dans son code, ou les
afficher dans des contrôles tels que les dbGrid
L'avantage de ce stockage intermédiaire par le BDE est le suivant:
- le Client peut effectuer des déplacements bi-directionnels dans ses données
- si le Client modifie une valeur, le BDE génère automatiquement
l'instruction Sql qui sera expédiée vers le Serveur pour modifier la
valeur de la Table
Parmi les inconvénients:
- le BDE gère apparemment plusieurs caches, avec quelques problèmes de
synchronisation entre ces divers caches
- cette gestion automatique est lourde et explique la taille du BDE (aussi
causée par la gestion de nombreux moteurs: Interbase, mais aussi dBase,
Paradox, Oracle etc)
7.4 - Interbase Express
Par rapport au BDE, Interbase Express simplifie le traitement en en
s'occupant que d'un seul type de Serveur: Interbase.
Les composants utilisés sont alors les suivants:
- IbDatabase associé à IbTransaction s'occupe de la connexion avec le
Client Interbase
- IbQuery traite les requêtes Sql en les envoyant vers le Serveur et en
tamponnant les requêtes SELECT
- le dbGrid usuel se charge de la visualisation et la saisie
7.5 - dbExpress
L'architecture dbExpress va un pas plus loin que IbX en séparant le stockage
de l'accès:
- SqlConnection s'occupe de la connexion avec le Client Interbase
- SqlQuery traite les requêtes Sql mais ne tamponne pas les données en
lecture
- le données échangées avec le Serveur utilisent:
- un composent tDataSetProvider qui met les données sous forme de paquets
pour normaliser les échanges avec le Client
- un tClientDataSet qui se charge de tamponner les données
- le dbGrid usuel se charge de la visualisation et la saisie
Le schéma correspondant est le suivant:
dbExpress possède aussi deux extensions:
- il est possible de séparer
- d'une part SqlConnection, SqlQuery et DataSetProvider sur une machine
intermédiaire, placée entre le Serveur et les Clients
- de l'autre les Clients contenant chacun un ClientDataset, et les
composants de contrôle visuel
Il s'agit alors d'une application 3 niveaux, utilisant pour communiquer
entre le PC du milieu et les Clients des composants de communications. Nous
n'utiliserons pas cette séparation, et laisserons tous les composants sur le
poste Client
- il est possible de travailler sans aucune connexion au Serveur: le
ClientDataSet travaille en mémoire pure, en sauvegardant le contenu de son
cache dans un fichier du Client (à un format binaire ou XML n'ayant rien à
voir avec Interbase). Il s'agit du travail nomade, illustré par ce schéma:
Ce type de traitement est appelé aussi par Borland "MyBase".
Nous allons nous intéresser dans la suite de cet article aux lectures et
modifications de tables Interbase en utilisant le tClientDataSet.
7.6 - Lecture dans un tClientDataSet
Voici notre première application pour afficher les données:
|