I. Introduction▲
Dans dbExpress avec Delphi 6 nous avons construit un accès simple à une table unique. Nous allons maintenant aborder deux types de relations :
- la relation d'une table maître avec une table détail ;
- la relation LookUp.
II. Ce qu'il vous faut▲
- Delphi 6 Pro ou Entreprise.
- Delphi 6 et InterBase 6 sur CD avec la Documentation sont aussi disponibles auprès du Centre Officiel de Borland : Diffus'Log - Tél : 01 34 63 07 01.
- Il vous faut aussi l'application et le fichier MaDatabase.gdb résultant de Delphi 6 et InterBase 6, ainsi que l'application développée dans dbExpress avec Delphi 6.
III. Création des tables complémentaires▲
Pour la création des tables, nous utilisons les IBX qui gèrent directement InterBase.
Pour cela, complétons l'application Delphi 6 et InterBase 6 dans le but de générer les tables :
À partir de la palette, placez sur le DataModule 2 IBTable,
et modifiez les propriétés pour la table Appels
Objet |
Propriété |
Valeur |
---|---|---|
IBTable1 |
Name |
IBTableAppels |
IBTableAppels |
Database |
IBDatabase1 |
IBTableAppels |
TableName |
APPELS Ignorez messages la base est fermée |
IBTableAppels |
FieldDefs |
cliquez sur … et tapez 5 fois sur la touche Ins |
Modifier les noms des champs ainsi que leurs propriétés : |
||
IBTableAppelsField1 |
Name |
PK_APPELS |
PK_APPELS |
DataType |
ftInteger |
PK_APPELS |
Attributes |
[faRequired] |
DATEAPPEL |
DataType |
ftDateTime |
TYPEDAPPEL |
DataType |
ftString |
TYPEDAPPEL |
Size |
12 |
RAPPELER |
DataType |
ftBoolean (sera traduit en SmallInt) |
COUT |
DataType |
ftCurrency (sera traduit en Double Precision) |
IBTableAppels |
FieldDefs |
cliquez sur … et tapez 1 fois sur la touche Ins |
Modifier le nom du champ ainsi que sa propriété : |
||
IBTableAppelsFieldIndex1 |
Name |
PK_APPELS |
PK_APPELS |
Options |
[ixPrimary] |
et les propriétés pour la table TypesDAppel
Objet |
Propriété |
Valeur |
---|---|---|
IBTable1 |
Name |
IBTableTypesDAppel |
IBTableTypesDAppel |
Database |
IBDatabase1 |
IBTableTypesDAppel |
TableName |
TYPESDAPPEL |
IBTableTypesDAppel |
FieldDefs |
cliquez sur … et tapez deux fois sur la touche Ins |
Modifier les noms des champs ainsi que leurs propriétés : |
||
IBTableTypesDAppelField1 |
Name |
PK_TYPESDAPPEL |
PK_TYPESDAPPEL |
DataType |
ftInteger |
PK_TYPESDAPPEL |
Attributes |
[faRequired] |
TYPEDAPPEL |
DataType |
ftString |
TYPEDAPPEL |
Size |
12 |
IBTableTyoesDAppel |
FieldDefs |
cliquez sur … et tapez une fois sur la touche Ins |
Modifier le nom du champ ainsi que sa propriété : |
||
IBTableAppelsFieldIndex1 |
Name |
PK_TYPESDAPPEL |
PK_TYPESDAPPEL |
Options |
[ixPrimary] |
On n'introduit pas d'autres composants, puisque notre seul but est de créer les tables.
Pour que les tables soient créées, on ajoute :
IBTableAppels.CreateTable;
IBTableTypesDAppel.CreateTable;
en fin de la méthode IBDatabase1Open.
Et on exécute une fois le programme.
Note : la création de tables à travers l'IDE comme ci-dessus ou par CREATE TABLE est une affaire de goût.
Ceux qui préfèrent CREATE TABLE, peuvent s'inspirer de Ma première base InterBase et lancer l'ordre suivant (qui n'est volontairement pas formaté pour permettre un copier/coller dans l'Interactive SQL d'IBConsole) :
CREATE
TABLE
"APPELS"
(
"PK_APPELS"
INTEGER
NOT
NULL
, "DATEAPPEL"
TIMESTAMP
,
"TYPEDAPPEL"
VARCHAR
(
12
)
, "RAPPELER"
SMALLINT
, "COUT"
DOUBLE
PRECISION
,
"PK_NOMS"
INTEGER
NOT
NULL
, CONSTRAINT
"PK_APPELS"
PRIMARY
KEY
(
"PK_APPELS"
)
)
;
CREATE
TABLE
"TYPESDAPPEL"
(
"PK_TYPESDAPPEL"
INTEGER
NOT
NULL
,
"TYPEDAPPEL"
VARCHAR
(
12
)
, CONSTRAINT
"PK_TYPESDAPPEL"
PRIMARY
KEY
(
"PK_TYPESDAPPEL"
)
)
;
Les tables étant créées, nous allons maintenant voir comment Delphi prend en compte la logique relationnelle.
IV. Relation mère/fille▲
Pour relier la table Appels à la forme, nous créons une chaîne dbExpress identique à celle que nous avons établie dans dbExpress avec Delphi 6 pour la table Noms. Il suffit d'ailleurs d'aller sur le data module, de sélectionner l'ensemble des composants sauf SQLConnection1, et de faire un copier/coller. (Les composants viennent se coller exactement sur les composants copiés : descendez-les tous en faisant [Ctrl + Maj + Bas] avant de les désélectionner.)
Il suffit maintenant d'adapter les propriétés :
Composant |
Propriété |
Valeur |
---|---|---|
SQLDataSet1 |
Name |
SQLDataSetAppels |
SQLDataSetAppels |
SQLConnection |
SQLConnection1 |
SQLDataSetAppels |
CommandText |
select * from APPELS |
DataSetProvider1 |
Name |
DataSetProviderAppels |
DataSetProviderAppels |
DataSet |
SQLDataSetAppels |
ClientDataSet1 |
Name |
ClientDataSetAppels |
ClientDataSetAppels |
ProviderName |
DataSetProviderAppels |
DataSource1 |
Name |
DataSourceAppels |
DataSourceAppels |
DataSet |
ClientDataSetAppels |
Comment allons-nous indiquer la liaison mère/fille ?
Tout simplement en indiquant que ClientDataSetAppels dépend de ClientDataSetNoms à l'aide des propriétés suivantes :
Composant |
Propriété |
Valeur |
---|---|---|
ClientDataSetAppels |
MasterSource |
DataSourceNoms |
ClientDataSetAppels |
MasterFields |
PK_NOMS (1) |
ClientDataSetAppels |
IndexFieldNames |
PK_NOMS;DATEAPPEL |
(1) Ne cliquez pas sur les … de la ligne MasterField : en le faisant, vous provoquez les choses suivantes :
- activation de la connexion SQLConnection1 ;
- chargement de FieldDefs ;
- ouverture d'une dual liste pour établir la liaison.
Évidemment, il est plus agréable d'avoir à choisir dans une liste. Mais vous pouvez souhaiter contrôler le moment de l'ouverture de la connexion à l'exécution en démarrant avec Connected à False. De plus, vous pouvez souhaiter que les champs FieldDefs du ClientDataSet soient reconstitués automatiquement à l'exécution pour refléter d'éventuelles modifications de la structure de la table. Si néanmoins vous avez affiché la dual liste, il vous suffit de :
- mettre dans l'IDE SQLConnection1.Connected à False ;
- et, toujours dans l'IDE, ClientDataSetAppels.StordeDefs à False.
Pour terminer, nous ajoutons la procédure d'ouverture de la table Appels :
procedure
TDataModule1.ClientDataSetAppelsOpen;
begin
ClientDataSetAppels.Open;
end
;
Sur la Forme UnitForm, nous plaçons une grille supplémentaire que nous connections à DataModule1.DataSourceAppels
Objet |
Propriété |
Valeur |
---|---|---|
DBGrid1 |
Name |
DBGridAppels |
et dans FormShow nous ajoutons l'ordre d'ouverture de la table Appels, ainsi que les mises à jour d'Appels :
procedure
TFormNoms.FormShow(Sender: TObject);
begin
DBGridNoms.DataSource := DataModule1.DataSourceNoms;
DataModule1.ClientDataSetNomsOpen;
DBGridAppels.DataSource := DataModule1.DataSourceAppels; DataModule1.ClientDataSetAppelsOpen;
end
;
procedure
TFormNoms.ButtonApplyUpdatesClick(Sender: TObject);
begin
DataModule1.ClientDataSetNoms.ApplyUpdates(-1
);
DataModule1.ClientDataSetAppels.ApplyUpdates(-1
);
end
;
procedure
TFormNoms.ButtonCancelUpdatesClick(Sender: TObject);
begin
DataModule1.ClientDataSetNoms.CancelUpdates;
DataModule1.ClientDataSetAppels.CancelUpdates;
end
;
Nous exécutons et saisissons : les valeurs de liaisons des appels sont préremplies automatiquement, et la relation est totalement gérée.
Cliquez sur Sauvegarder les modifications avant de sortir de l'application.
Votre premier programme relationnel est prêt.
V. Relation lookup▲
Nous allons maintenant ajouter un contrôle sur la zone TypeDAppel. En effet, nous souhaitons que ce type appartienne à la table TypesDAppel que nous avons créée au début.
Nous ajoutons la connectique dbExpress de cette table. C'est maintenant une opération qui devient une habitude : il suffit de répéter ce que nous avons fait pour la table Appels pour obtenir ceci :
Vérifiez sur les composants de la rangée du bas, que vous avez bien mis TypesDAppel partout où il y avait Appels et que vous avez :
select
*
from
TYPESDAPPEL
Créez la procédure d'ouverture :
procedure
TDataModule1.ClientDataSetTypesDAppelOpen;
begin
ClientDataSetTypesDAppel.Open;
end
;
Ajoutez une grille sur la forme pour saisir les types d'appels, et complétez les procédures :
procedure
TFormNoms.FormShow(Sender: TObject);
begin
DBGridNoms.DataSource := DataModule1.DataSourceNoms;
DataModule1.ClientDataSetNomsOpen;
DBGridTypesDAppel.DataSource := DataModule1.DataSourceTypesDAppel; DataModule1.ClientDataSetTypesDAppelOpen;
DBGridAppels.DataSource := DataModule1.DataSourceAppels; DataModule1.ClientDataSetAppelsOpen;
end
;
procedure
TFormNoms.ButtonApplyUpdatesClick(Sender: TObject);
begin
DataModule1.ClientDataSetNoms.ApplyUpdates(-1
);
DataModule1.ClientDataSetTypesDAppel.ApplyUpdates(-1
);
DataModule1.ClientDataSetAppels.ApplyUpdates(-1
);
end
;
procedure
TFormNoms.ButtonCancelUpdatesClick(Sender: TObject);
begin
DataModule1.ClientDataSetNoms.CancelUpdates;
DataModule1.ClientDataSetTypesDAppel.CancelUpdates;
DataModule1.ClientDataSetAppels.CancelUpdates;
end
;
Il nous ne reste qu'à relier cette table avec le champ TypeDAppel de la table appel
Nous allons utiliser la propriété PickList associée à la colonne TypeDAppel de la table Appels.
Dans la forme nous ajoutons la procédure privée suivante :
procedure
TFormNoms.SetTypesDAppelPickList;
var
s: string
;
begin
s := ''
;
with
DataModule1.ClientDataSetTypesDAppel do
begin
First;
while
not
Eof do
begin
s := s + FieldByName('TYPEDAPPEL'
).AsString + #13
;
Next;
end
;
end
;
DBGridAppels.Columns[2
].PickList.Text := Copy(s, 1
, Length(s) - 1
);
end
;
Cette procédure de rafraîchissement de la liste est activée à la fin de FormShow et de ApplyUpdates en ajoutant la ligne :
SetTypesDAppelPickList;
à la fin des procédures FormShow et ButtonAppluUpdatesClick.
Votre relation LookUp est prête pour la saisie.
VI. Pour aller plus loin▲
- Consultez les forums Delphi ainsi que Delphi et bases de données de www.developpez.com
- Abonnez-vous au news group Base de données (en français) (news://news.vienneinfo.org/nzn.fr.base-de-donnees).