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:
Notez l'ordre de chaînage des composants:
Cet ordre provient des multiplicités possibles: - une tSqlConnection peut être reliée à plusieurs tSqlQueries
- un tSqlQuery peut être relié à plusieurs tDatasetProviders
- un tDataSetProvider peut alimenter plusieurs tClientDatasets
- un tClientDataSet peut être relié à plusieurs tDataSource
- un tDataSource peut être relié à plusieurs composants visuels tels que la tdbGrid
Si Delphi avait proposé au développeur programmeur de relier tSqlConnection à ses tSqlQueries, il aurait fallu prévoir une LISTE de tSqlQueries associés,
alors que dans l'ordre inverse, chaque tSqlQuery ne peut avoir qu'une tSqlConnection, donc une seule ligne dans l'Inspecteur d'Objet.
Vous pouvez télécharger le sources du projet "ib_dbx_read.zip".
8 - Modifier des Données 8.1 - Principe
Pour modifier les données en utilisant le tClientDataset, l'utilisateur va travailler en deux étapes: - toutes les modifications (ajout, changement, effacement) sont mémorisés par le tClientDataSet
- lorsqu'il le souhaite, l'utilisateur peut envoyer les modifications vers le Serveur Interbase
L'utilisateur travaille donc dans un premier temps uniquement avec la mémoire
du tClientDataSet. Celui-ci garde la trace intégrale de toutes les modifications: - si nous modifions un enregistrement, nous aurons 6 fois l'enregistrement en mémoire (l'original et les 5 modifications)
- les ajouts sont placés dans la mémoire
- les effacements sont mémorisés comme une nouvelle ligne avec une marque d'effacement.
8.2 - Les Modifications de tClientDataset
Le tClientDataset contient donc une suite de lignes numérotées: - les lignes chargées lors de l'ouverture de tClientDataset
- les lignes ajoutées
- les versions modifiées de lignes précédentes
- les lignes effacées
Le dbGrid ne présente quant à lui que la dernière version de chaque ligne. Pour visualiser les lignes originales et leurs versions successives, nous
allons simplement sauvegarder le tClientDataset dans un fichier .XML et réafficher ce fichier .XML. Ce type d'analyse a été présenté dans l'article
Affichage ClientDataset XML. Nous nous contenterons ici d'appeler les classes d'analyse et d'affichage. Par conséquent:
A présent voici un exemple de manipulation: | cliquez sur le bouton "open_cds_" |
| l'application ouvre la table et l'affiche | |
ajoutez une ligne dans le dbGrid 6 Delphi Asp.Net 3 1.400 et postez la en remontant dans la dbGrid |
| cliquez "save_as_xml_" pour sauver le contenu de ClientDataSet dans le fichier RESU.XML |
| allez dans le répertoire de l'exécutable et cliquez RESU.XML | |
Internet Explorer affiche le contenu du fichier .XML: | |
cliquez "display_xml_" pour visualiser les lignes de ce fichier .XML: | | le programme affiche ce contenu:
| Vous pouvez ainsi effectuer toutes les opérations (ajout, effacement, modifications) que vous souhaitez, en prenant bien soin de:
- provoquer le ClientDataSet.Post par changement de ligne dans le dbGrid après les modification
- en sauvegardant le résultat de ces modifications en cliquant "save_as_xml_" si vous souhaitez conserver ces modifications
8.3 - Principe de la mise à jour du Serveur Pour que les modifications effectuées (ajout, effacement, modification) soient enregistrées dans la Table du Serveur Interbase, il suffit d'appeler:
nombre_erreurs:= tClientDataSet.ApplyUpdates(-1); Le tClientDataSet va alors envoyer vers le Serveur (via le tDatasetProvider,
le tSqlQuery, le tSqlConnection) les instructions SQL qui effectueront les modifications. Si le Serveur ne peut effectuer la modification demandée, il retourne une
erreur en indiquant le motif du refus. Pour gérer ces les erreurs, nous pouvons créer l'événement OnReconcileError du tClientDataset. Les paramètres sont les suivants: PROCEDURE ReconcileError(
p_c_data_set: TCustomClientDataSet; p_c_error: EReconcileError; p_update_kind: TUpdateKind; VAR pv_action: TReconcileAction); et:
- p_c_data_set: c'est le tClientDataSet qui contient les erreurs
- p_c_error: une exception contenant dans p_c_error.Message le texte de l'exception
- p_update_kind indique si l'erreur provenant d'un ajout (ukInsert), d'une modification (ukModify) ou d'un effacement (ukDelete)
- pv_action: indique ce qu'il faut faire de cette erreur (annuler, forcer la
valeur etc)
Et Borland suggère même d'utiliser un dialogue tout préparer pour proposer à l'utilisateur de décider ce qu'il faut faire en lui présentant directement le
problème et le le laissant choisir le traitement à effectuer. Ce dialogue appelé RECERROR.PAS se trouve dans: C:\PROGRAM FILES\BORLAND\DELPHI6\OBJREPOS et a l'allure suivante: et:
- il affiche l'erreur
- présente les données ayant causé la faute
- laisse l'utilisateur décider ce qu'il souhaite faire
Pour utiliser ce dialogue: Finalement pour comprendre les commandes que Delphi génère pour nous lors de
l'appel de tClientDataset.ApplyUpdates, nous allons employer un SqlMonitor qui affiche les API Interbase envoyées vers le Serveur Interbase. Pour cela il suffit de
- relier le tSqlMonitor à tSqlConnection
- basculer tSqlMonitor sur True
- créer l'événement tSqlMonitor.OnLogTrace et visualiser tSqlMonitor.TraceList
Ajoutons ces éléments à notre application: | posez un tButton "ApplyUpdates_" sur la Forme et faites lui mettre à jour le serveur:
procedure TForm1.ApplyUpdates_Click(Sender: TObject);
var l_erreurs: Integer; begin
l_erreurs:= ClientDataSet1.ApplyUpdates(-1);
display('erreurs '+ IntToStr(l_erreurs));
end; // ApplyUpdates_Click | |
| ajoutez à la liste des USES la forme de réconciliation: USES .... recerror, ... |
| créez le gestionnaire d'erreur: - sélectionnez ClientDataset1
- créez son événement OnReconcileError
- appelez la Forme de réconciliation et retournez le code à Delphi:
procedure TForm1.ClientDataSet1ReconcileError(
DataSet: TCustomClientDataSet; E: EReconcileError;
UpdateKind: TUpdateKind; var Action: TReconcileAction);
begin
action:= HandleReconcileError(DataSet, UpdateKind, e);
end; // ClientDataSet1ReconcileError | |
| ajoutez la trace Sql: - sélectionnez dans la page "dbExpress" de la Palette le composant SqlMonitor:
- Posez-le sur la tForm.
- sélectionnez SqlConnection et mettez-y SqlConnection1
- sélectionnez Active et basculez le sur True
- créez son événement OnLogTrace et affichez les textes:
var g_trace_count: Integer= 0;
procedure TForm1.SQLMonitor1LogTrace(Sender: TObject;
CBInfo: pSQLTRACEDesc); begin
with SQLMonitor1, TraceList do
while g_trace_count< Count do
begin
display(Strings[g_trace_count]);
Inc(g_trace_count);
end; end; // SQLMonitor1LogTrace |
| | compilez |
8.4 - Chargement du fichier .XML
Si nous avons sauvegardé dans un fichier .XML un tClientDataSet qui a été modifié via le dbGrid (et que les modifications n'ont pas encore été envoyée au Serveur), nous pouvons charger les données du fichier .XML en appelant:
tClientDataset.LoadFromFile(nom_fichier); Les données originales et TOUTES les modifications sont alors chargées dans le tClientDataset. Ajoutons cette possibilité à notre application:
| posez un tButton "load_xml_" sur la Forme et faites lui charge le fichier .XML:
ClientDataset1.LoadFromFile('resu.XML'); | | compilez |
8.5 - Mise à jour d'un ajout Prenons tout d'abord le cas d'un ajout. Nous avons vu que l'instruction SQL pour ajouter est du type:
INSERT INTO FORMATIONS (f_numero, f_nom, f_jours, f_prix)
VALUES (6, 'ASP.Net Delphi', 3, 1400) | Vérifions que dbExpress génère bien une instruction de ce type pour ajouter notre ligne à la Table:
ATTENTION: dans l'instruction SQL de SqlQuery, nous avons placé: et non PAS La différence est capitale:
8.6 - Effacement
Pour effacer une ligne, il faut envoyer l'instruction Sql: DELETE
FROM FORMATIONS WHERE f_numero= 2 |
Le WHERE est optionnel, mais si vous ne dites pas comment le Serveur doit sélectionner la ligne à effacer, il effacera tout. Quel est le code utilisé par dbExpress ? Eh bien il suffit de regarder:
| allez dans le dbGrid sur la ligne "4 / Composants Delphi" et supprimez la ligne en tapant Ctrl + Suppression
(enfoncez la touche Contrôle et la touche Suppression tout en maintenant Ctrl enfoncée) | | Delphi vous demande de confirmer : "Delete Record ?"
| | cliquez Ok | | la ligne disparaît du dbGrid |
| examinez, par curiosité, le contenu du tClientDataset - cliquez "save_as_xml_"
- cliquez "display_xml_"
La ligne a bien disparu du dbGrid et le code de la ligne dans le fichier .XML est le code d'une ligne effacée |
| envoyez l'effacement vers le Serveur en cliquant "ApplyUpdate_" |
Nous constatons que dbExpress a utilisé dans WHERE TOUS les champs de la table. Ceci signifie que: - la ligne n'est effacée que si elle a conservé la valeur qu'elle avait
lorsque nous l'avons chargé (depuis le Serveur ou depuis le fichier .XML)
- si un autre utilisateur avait changé la moindre valeur (le numéro de ligne, un accent aigu quelque part, une décimale du prix...) le Serveur n'aurait
pas pu trouver la ligne et ne l'aurait pas effacée.
Nous pouvons vérifier ceci en "simulant" l'action d'un second utilisateur qui va modifier une ligne: |
exécutez le programme et ouvrez le ClientDataset (par "open_cds_" ou "load_xml_") | | faites modifier une valeur par un SECOND utilisateur
- ouvrez un Explorateur Windows
- lancez P_IB_DBX_MODIFY.EXE
- sélectionnez la ligne "1 / Initiation Delphi", modifiez le prix en 1350, et postez en changeant de ligne
- envoyez le changement vers le Serveur en cliquant "ApplyUpdates_"
- fermez cet .EXE
|
| à présent essayez d'effacer la ligne modifiée par l'autre utilisateur dans le programme lancé depuis Delphi: - allez dans le dbGrid sur la ligne "1 / Initiation Delphi"
- tapez
Ctrl + Suppression
- Delphi indique qu'il ne trouve pas la ligne ayant exactement les mêmes valeurs:
Vous noterez que: - notre affichage (en arrière plan) indique bien:
reconcile Record not found or changed by another user Pas de quoi être surpris, nous avons tout fait pour ! - le dialogue:
- présente le même message à l'utilisateur
- affiche les valeurs actuelles de l'enregistrement
- suggère l'action "Skip" (annuler l'effacement)
| |
cliquez sur "Ok", ce qui annulera l'effacement | | sauvegardes le contenu de ClientDataset1 en cliquant "save_as_xml_" |
Aurions nous pu tout de même effacer l'enregistrement ? Oui, à condition de fournir une instruction Sql qui corresponde à un enregistrement existant. Dans notre cas, l'"autre" utilisateur n'a fait que changer le prix. Les autres
champs n'ont pas été modifiés. Si nous effectuions une spécification de l'enregistrement par f_numero uniquement, le Serveur aurait bien pu trouver l'enregistrement numéro 2 et l'effacer.
Pour que dbExpress génère une requête d'effacement qui n'utilise que la colonne f_numero, il faut que nous modifions la valeur de DatasetProvider.UpdateMode. En effet:
- par défaut, la valeur est UpWhereAll qui indique justement que le WHERE contiendra la valeur de tous les champs
- si nous sélectionnons UpWhereKeyOnly, seule la clé sera utilisée pour
construire la requête
Commençons par ajouter un index à notre table: | créez une nouvelle application et nommez-la "ib_dbx_add_index" |
| 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" -> Interbase "Connection Name" -> IbLocal
"DataBase" -> ..\\data\\institut_pascal.gdb "Dialect" -> 3 "User Name" -> SYSDBA "Pass Word" -> masterkey
Allez dans l'Inspecteur d'Objet: - sélectionnez LoginPrompt et basculez sa valeur sur False
- vérifiez la connection en basculant Connected sur True, puis fermez la
connection en basculant Connected sur False.
| | sélectionnez dans la page "dbExpress" de la Palette le composant SqlQuery
et posez-le sur la tForm. - Sélectionnez sa propriété SqlConnection et initialisez-la à SqlConnection1
| |
posez un tButton "add_index_" sur la Forme et faites lui créer notre index. L'instruction Sql est:
CREATE INDEX x_numero ON formations | et la procédure sera:
var g_trace_count: Integer= 0;
procedure TForm1.SQLMonitor1LogTrace(Sender: TObject;
CBInfo: pSQLTRACEDesc); begin
with SQLMonitor1, TraceList do
while g_trace_count< Count do
begin
display(Strings[g_trace_count]);
Inc(g_trace_count);
end; end; // SQLMonitor1LogTrace |
| | puisque nous y sommes, autant ajouter la suppression de l'index: posez un
tButton "drop_index_" sur la Forme et faites lui supprimer notre index: | | compilez et exécutez |
Nous aurons alors:
Las, après essai, il s'avère que l'index seul ne suffit pas: il faut une CLE PRIMAIRE (un index UNIQUE, NOT NULL). Et NOT NULL ne peut apparemment pas être ajouté à une table existante, sauf via la modification de la colonne
RDB$NULL_FLAG de la colonne de la table RDB$RELATION_FIELDS, ce qui nous entraînerait trop loin. Nous avons donc choisi de recréer la table formations avec une clé primaire:
| créez une nouvelle application et nommez-la "ib_dbx_create_table_pk" | |
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" -> Interbase
"Connection Name" -> IbLocal "DataBase" -> ..\\data\\institut_pascal.gdb "Dialect" -> 3
"User Name" -> SYSDBA "Pass Word" -> masterkey Allez dans l'Inspecteur d'Objet: - sélectionnez LoginPrompt et basculez sa valeur sur False
- vérifiez la connection en basculant Connected sur True, puis fermez la connection en basculant Connected sur False.
| |
sélectionnez dans la page "dbExpress" de la Palette le composant SqlQuery et posez-le sur la tForm. - Sélectionnez sa propriété SqlConnection et initialisez-la à SqlConnection1
|
| posez un tButton "create_table_primary_key_" sur la Forme et faites lui créer une table avec une clé primaire. L'instruction Sql est:
CREATE TABLE formations (
f_numero INTEGER NOT NULL PRIMARY KEY, f_nom CHAR(23),
f_jours SMALLINT,' f_prix NUMERIC(12, 2) ) | et la procédure sera:
procedure TForm1.create_table_with_primary_key_Click(Sender: TObject);
begin
with SqlQuery1 do
begin Close;
with Sql do
begin Clear;
Add('CREATE TABLE formations');
Add(' ('
+' f_numero INTEGER NOT NULL PRIMARY KEY,');
Add(' f_nom CHAR(23),');
Add(' f_jours SMALLINT,');
Add(' f_prix NUMERIC(12, 2)');
Add(' )');
end; // with Sql
Try
SqlConnection1.Open;
ExecSql;
display(' ok');
except
on e: Exception do
begin
display(' *** pb_create '+ e.Message);
end; end;
end; // with SqlQuery1
end; // create_table_Click | |
| posez un tButton "drop_table_" sur la Forme pour pouvoir supprimer la table existante, et faites lui exécuter:
|
| compilez et exécutez | | cliquez "drop_table_" |
| cliquez "create_table_with_primary_key_" | Peuplez à nouveau la table: |
lancez l'exécutable "P_IB_DBX_INSERT_DATA.EXE" et générez les valeurs pour la table formations en cliquant "insert_batch_" |
A présent essayons d'effacer notre ligne:
| réouvrez "ib_dbx_modify" | | modifiez le mode de génération de la requête d'effacement:
- sélectionnez DatasetProvider1
- sélectionnez sa propriété UpdateMode et donnez-lui la valeur UpWhereKeyOnly
| |
compilez et exécutez |
Et pour effacer:
8.7 - Modification de données
La modification se fait de façon similaire. L'instruction Sql à utiliser est: UPDATE formations
SET f_nom= 'UML et Design Patterns Delphi' WHERE f_numero= 5 |
Le problème est donc le même que pour l'effacement: - si tDatasetProvider.UpdateMode a la valeur UpWhereAll, dbExpress va générer une instruction qui tente de remplacer la ligne en supposant que
personne ne l'a modifié depuis notre lecture initiale
- si tDatasetProvider.UpdateMode a la valeur UpWhereKeyOnly, dbExpress va générer une instruction qui tente de remplacer la ligne ayant la même clé
primaire que notre ligne
- si tDatasetProvider.UpdateMode a la valeur UpWhereChanged, dbExpress va générer une instruction qui tente de remplacer la ligne ayant dans les
champs que nous avons modifié les valeurs que ces champs avaient avant modification
Prenons, par exemple, le cas UpWhereKeyOnly:
9 - Télécharger les Exemples
Nous avons placé tous les projets dans des .ZIP qui 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ées
- 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. Voici les .ZIP:
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
- l'affichage du contenu d'un fichier .XML correspondant à la sauvegarde locale d'un tClientDataset est présenté dans Affichage ClientDataset XML
- 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. |