|
HOWTO Accueil
HOWTO développement Sashipa
Gérer deux niveaux de clefs-étrangères.
Dans le même écran que votre cardForm, vous souhaitez afficher une listForm qui
contient les données qui référencent les données d'une autre table, qui
référence la table de votre cardForm.
Préparation
Voici tout d'abord le script SQL de la base sur laquelle on va travailler
(ici avec la syntaxe HSQL) :
CREATE TABLE Organisme (
Id_Organisme integer not null primary key,
Nom varchar(100) not null
);
CREATE TABLE Section (
Id_Section integer not null primary key,
Ref_Organisme integer not null,
Nom varchar(100) not null,
FOREIGN KEY (Ref_Organisme) REFERENCES Organisme (Id_Organisme)
);
CREATE TABLE Personne (
Id_Personne integer not null primary key,
Ref_Section integer not null,
Nom varchar(100) not null,
FOREIGN KEY (Ref_Section) REFERENCES Section (Id_Section)
);
|
Nous avons des Organismes qui contiennent plusieurs Sections, qui contiennent
elles-même plusieurs Personnes. Nous souhaitons afficher la liste des
Personnes dans la fiche Organisme.
Problématique :
L'affichage simple des personnes dans une listForm est relativement simple
en soit (il suffit d'une jointure), l'affaire se complique si l'on souhaite
permettre l'ajout d'une personne depuis le bouton ajouter de la listForm.
En effet, dans ce cas il est préférable que le choix des sections dans la
fiche Personne, se limite aux sections de l'organisme.
La fiche Organisme
Commençons par le code de la fiche Organisme :
<screen name='SCtblOrganisme'>
<title>Fiche d'un organisme</title>
<formSet>
<cardForm db='dbDemo'>
<title>Fiche d'un organisme</title>
<location x='10' y='10' />
<cardSchemaTableRef schemaTable='tblOrganisme' queries='sudi'
updateAfterInsert='yes' multipleInsert='no' />
<fieldContainer>
<textField>
<schemaColumnRef schemaColumn='tblOrganisme_Nom' />
</textField>
</fieldContainer>
</cardForm>
<!-- ... listForm des sections ... -->
<listForm db='dbDemo' doubleClicScreen='SCtblPersonne'
delete='yes'>
<title>Personnes (Sections)</title>
<bounds x='360' y='10' w='300' h='400' />
<selectQueryBuilder type='list'>
<castFilterSet autoCastFilter='no'>
<fkCastFilter>
<instanceFk schemaFk='fk_tblSection_tblOrganisme' />
</fkCastFilter>
</castFilterSet>
<fromStatementBuilder>
<mainInstanceTable schemaTable='tblPersonne' />
<fkJoin join='inner'>
<instanceFk schemaFk='fk_tblPersonne_tblSection' />
</fkJoin>
</fromStatementBuilder>
</selectQueryBuilder>
<instanceColumnList>
<instanceColumn schemaColumn='tblSection_Nom' >
<title>Direction</title>
</instanceColumn>
<instanceColumn schemaColumn='tblPersonne_Nom' />
</instanceColumnList>
<insertScreen screen='SCtblPersonne'
schemaFk='fk_tblPersonne_tblSection' />
</listForm>
</formSet>
</screen>
|
Explications :
Le castFilter est celui de la clef étrangère de la table Section, qui
référence la table Organisme. Il attend donc comme filtre, une valeur
de clef primaire d'Organisme. C'est en effet le filtre disponible pour
la fiche Organisme.
On définit une jointure entre la table Personne (celle des colonnes de
la listForm) et la table Section (celle de la clef étrangère du
castFilter). Elle est de type 'inner' puisque toutes les personnes
qui nous intéressent ont leur clef étrangère de renseignée (elles
référencent nécessairement une section).
L'écran d'ajout de personne est la fiche Personne. On précise la clef
étrangère qui est concernée par le filtre de la fiche appelante (ie.
notre fiche Organisme). Il s'agit de : fk_tblPersonne_tblSection.
La fiche Section n'a rien de particulier, passons directement à la fiche
Personne.
La fiche Personne
Dans cette fiche, la particularité est la requête de la combo-box qui propose
les Sections. Focalisons-nous sur cette requête :
<screen name='SCtblPersonne'>
<title>Fiche d'une personne</title>
<formSet>
<cardForm db='dbDemo'>
<title>Fiche d'une personne</title>
<location x='10' y='10' />
<cardSchemaTableRef schemaTable='tblPersonne' queries='sudi'
updateAfterInsert='no' multipleInsert='yes' />
<fieldContainer>
<comboBoxFkField>
<schemaFkRef schemaFk='fk_tblPersonne_tblSection' />
<go screen='SCtblSection' />
<choose screen='SCtblSection' />
<selectQueryBuilder distinctRequired='yes'>
<castFilterSet autoCastFilter='no'>
<pkCastFilter>
<instanceTable schemaTable='tblOrganisme' />
</pkCastFilter>
<pkCastFilter>
<instanceTable schemaTable='tblSection'
nickName='sec2' />
</pkCastFilter>
<pkCastFilter>
<instanceTable schemaTable='tblPersonne'
nickName='pers2' />
</pkCastFilter>
</castFilterSet>
<fromStatementBuilder>
<mainInstanceTable schemaTable='tblSection' />
<fkJoin join='inner'>
<instanceFk schemaFk='fk_tblSection_tblOrganisme' />
</fkJoin>
<fkJoin join='inner'>
<instanceFk schemaFk='fk_tblSection_tblOrganisme'>
<startInstanceTable schemaTable='tblSection'
nickName='sec2' />
</instanceFk>
</fkJoin>
<fkJoin join='left'>
<instanceFk schemaFk='fk_tblPersonne_tblSection'>
<startInstanceTable schemaTable='tblPersonne'
nickName='pers2' />
</instanceFk>
<referencedInstanceTable schemaTable='tblSection'
nickName='sec2' />
</fkJoin>
</fromStatementBuilder>
</selectQueryBuilder>
</comboBoxFkField>
<textField>
<schemaColumnRef schemaColumn='tblPersonne_Nom' />
</textField>
</fieldContainer>
</cardForm>
</formSet>
</screen>
|
Les castFilters...
Lors de l'ouverture d'une fiche en mode Ajout, la fiche n'est pas filtrée. Le
filtre de l'écran appelant - s'il existe - circule tout de même mais les
fkFields l'ignorent, à une exception près. Il est en effet possible de
spécifier une clef étrangère lors de la déclaration de l'élément
insertScreen de la fiche appelante. Si elle existe, alors le fkField
qui travaille sur cette clef étrangère aura accès au filtre de l'appelant.
C'est par ce mécanisme que la combo-box de notre écran ici, pourra être filtrée
en mode ajout avec le filtre de la fiche Organisme.
Voyons le rôle des différents castFilters :
Le premier castFilter attend une clef primaire de la table Organisme. Il
s'activera donc lors d'un ajout de Personne depuis la fiche Organisme.
Le deuxième attend une clef primaire de la table Section. Il
s'activera donc lors d'un ajout de Personne depuis la fiche Section.
Le troisième attend une clef primaire de la table Personne. Il
s'activera donc lors de l'ouverture d'une fiche Personne existante, pour
modification.
La clause From...
Nous opérons une série de jointures. Nous partons de la table Section, nous
faisons une jointure sur l'organisme référencé, puis une jointure sur
l'ensemble des sections de cette organisme, puis une jointure gauche
('left') sur les personnes de ces sections.
En bref :
Section (défaut) - Organisme (défaut) - Section (sec2) - Personne (per2)
Les colonnes affichées (clause Select) seront celles de l'instance
par défaut de la table Section. Les castFilters portent sur les trois autres
instances de tables, dans le but d'afficher les sections de l'Organisme
courant.
Un dernier mot à propos de la jointure de la table Personne :
Cette jointure nous oblige à agréger le résultat de la requête
(distinctRequired='yes'), sous peine de multiplication des
sections par le nombre de leurs personnes.
La jointure est nécessairement gauche ('left') puisque l'on
souhaite afficher toutes les directions de l'Organisme courant, y
compris quand il n'y a pas de Personnes.
Top
|