|
HOWTO Accueil
HOWTO développement Sashipa
Rendre la liste d'un fkField dépendante d'un autre.
Vous avez deux fkFields sur la même fiche (cardForm) et vous souhaitez que lorsque
l'utilisateur fait un choix dans la première, la deuxième liste change en fonction
du choix dans la première.
Exemple avec deux clefs étrangères enregistrées
Voyons un exemple concret : nous avons des Groupes de Personnes. Les
groupes font des Voyages, chaque voyage est organisé par une personne du
groupe. Voici le script SQL des tables (ici avec la syntaxe pour HSQL) :
CREATE TABLE Groupe (
Id_Groupe integer not null primary key,
Nom_Groupe varchar(100) not null
);
CREATE TABLE Personne (
Id_Personne integer not null primary key,
Ref_Groupe integer not null,
Nom_Personne varchar(100) not null,
Prenom_Personne varchar(100),
FOREIGN KEY (Ref_Groupe) REFERENCES Groupe (Id_Groupe)
);
CREATE TABLE Voyage (
Id_Voyage integer not null primary key,
Ref_Groupe integer not null,
Ref_Personne_Organisatrice integer,
Libelle_Voyage varchar(100) not null,
FOREIGN KEY (Ref_Groupe) REFERENCES Groupe (Id_Groupe),
FOREIGN KEY (Ref_Personne_Organisatrice) REFERENCES Personne (Id_Personne)
);
|
Une Personne appartient à un Groupe. Un Voyage est effectué par un Groupe et organisé
par une Personne organisatrice.
Dans la fiche du Groupe on aimerait choisir la personne organisatrice parmis les
personnes référençant le groupe seulement. L'utilisateur aura donc à choisir le
groupe avant la personne.
Tout se passe dans la requête du fkField dépendant. Voici le code :
<cardForm db='dbBase'>
<title>Fiche d'un voyage</title>
<location x='10' y='10' />
<cardSchemaTableRef schemaTable='tblVoyage' updateAfterInsert='no'
multipleInsert='yes' queries='sudi' />
<fieldContainer>
<readOnlyTextFkField name='fieldGroupe'>
<schemaFkRef schemaFk='fk_tblVoyage_tblGroupe' />
<go screen='SCtblGroupe' />
<choose screen='SItblGroupe_For_tblVoyage' />
</readOnlyTextFkField>
<comboBoxFkField>
<schemaFkRef schemaFk='fk_tblVoyage_tblPersonne' />
<go screen='SCtblPersonne' />
<selectQueryBuilder>
<castFilterSet filterSensitive='no' />
<whereStatementBuilder>
<criteriaBuilder mode='and' defaultSubEmptyAction='stuck'
emptyAction='stuck'>
<researchCriteria>
<castSchemaValue>
<fkCastFilter>
<instanceFk schemaFk='fk_tblPersonne_tblGroupe' />
</fkCastFilter>
</castSchemaValue>
<fieldRef field='fieldGroupe' />
</researchCriteria>
</criteriaBuilder>
</whereStatementBuilder>
</selectQueryBuilder>
</comboBoxFkField>
<textField>
<schemaColumnRef schemaColumn='tblVoyage_LibelleVoyage' />
</textField>
</fieldContainer>
</cardForm>
|
Remarques :
Le champ dont on va rendre notre requête dépendante est nommé (ici
fieldGroupe).
On déclare la requête comme insensible aux filtres (filterSensitive='no')
de la fiche, comme ça pas d'effets de bord.
L'élément researchCriteria contient un castSchemaValue, qui attend les
valeurs pour la clef étrangère fk_tblPersonne_tblGroupe (c'est à dire une clef
primaire de groupe). Et il va chercher ces valeurs dans le champ fieldGroupe.
Les attributs defaultSubEmptyAction='stuck' et emptyAction='stuck'
signifient que le champ est bloqué si le researchCriteria n'opère pas. Donc ici
le choix de la personne sera bloqué tant qu'un groupe ne sera pas choisi.
Exemple avec une seule clef étrangère enregistrée
Plus fort maintenant : prenons une table de Voyages qui référencent un pays, et
chaque pays référence un continent. Voici le script SQL des tables (syntaxe HSQL) :
CREATE TABLE Continent (
Id_Continent integer not null primary key,
Nom_Continent varchar(100) not null
);
CREATE TABLE Pays (
Id_Pays integer not null primary key,
Ref_Continent integer not null,
Nom_Pays varchar(100) not null,
FOREIGN KEY (Ref_Continent) REFERENCES Continent (Id_Continent)
);
CREATE TABLE Voyage (
Id_Voyage integer not null primary key,
Ref_Pays integer not null,
Libelle_Voyage varchar(100) not null,
FOREIGN KEY (Ref_Pays) REFERENCES Pays (Id_Pays)
);
|
Nous avons une table Voyage qui référence un Pays, qui référence un continent.
Dans la fiche du Voyage, nous souhaitons que l'utilisateur choisisse d'abord
un continent, puis le pays parmis ceux du continent. Mais bien sûr, seule la
référence au pays sera sauvée. On pourrait croire que ce cas est plus simple
que le précédent. Au contraire, un nouveau problème apparaît pour initialiser
le champ du continent.
Voici le code Sashipa des champs de la fiche (cardForm) d'un Voyage ; l'explication
est derrière.
<!-- Continent non sauve, mais selectionne -->
<comboBoxFkField name='fieldContinent' save='no'
dependentOfMainSelectQueryBuilder='no'>
<schemaFkRef schemaFk='fk_tblPays_tblContinent' />
<defaultSelectedValue>
<selectQueryBuilder>
<castFilterSet stuckWhenNoFilter='yes' autoCastFilter='no'>
<pkCastFilter>
<instanceTable schemaTable='tblVoyage' />
</pkCastFilter>
</castFilterSet>
<selectStatementBuilder>
<instanceColumnList>
<instanceFk schemaFk='fk_tblPays_tblContinent' />
</instanceColumnList>
</selectStatementBuilder>
<fromStatementBuilder>
<mainInstanceTable schemaTable='tblPays' />
<fkJoin join='inner'>
<instanceFk schemaFk='fk_tblVoyage_tblPays' />
</fkJoin>
</fromStatementBuilder>
</selectQueryBuilder>
</defaultSelectedValue>
<go screen='SCtblContinent' />
</comboBoxFkField>
<!-- Pays dependant de Continent -->
<comboBoxFkField>
<schemaFkRef schemaFk='fk_tblVoyage_tblPays' />
<go screen='SCtblPays' />
<choose screen='SCtblPays' />
<selectQueryBuilder>
<castFilterSet filterSensitive='no' />
<whereStatementBuilder>
<criteriaBuilder mode='and' defaultSubEmptyAction='stuck'
emptyAction='stuck'>
<researchCriteria>
<castSchemaValue>
<fkCastFilter>
<instanceFk schemaFk='fk_tblPays_tblContinent' />
</fkCastFilter>
</castSchemaValue>
<fieldRef field='fieldContinent' />
</researchCriteria>
</criteriaBuilder>
</whereStatementBuilder>
</selectQueryBuilder>
</comboBoxFkField>
|
Tout d'abord, les remarques concernant le fkField dépendant (le deuxième) sont les mêmes
qu'auparavant :
Le champ dont on va rendre notre requête dépendante est nommé (ici
fieldContinent).
On déclare la requête comme insensible aux filtres (filterSensitive='no')
de la fiche, comme ça pas d'effets de bord.
L'élément researchCriteria contient un castSchemaValue, qui attend les
valeurs pour la clef étrangère fk_tblPays_tblContinent (c'est à dire une clef
primaire de Continent). Et il va chercher ces valeurs dans le champ fieldContinent.
Les attributs defaultSubEmptyAction='stuck' et emptyAction='stuck'
signifient que la requête (et donc le contenu du champ) est bloquée si le researchCriteria
n'opère pas. Ici, le choix du Pays sera bloqué tant qu'un Continent ne sera pas choisi.
Il y a du nouveau dans le premier fkField. On remarque avant tout que ce champ ne sera
pas sauvegardé (save='no') et qu'il ne prendra pas sa valeur dans la requête de la
fiche (dependentOfMainSelectQueryBuilder='no').
De plus, on définit un élément defaultSelectedValue qui va se charger de
sélectionner le Continent qui correspond au Pays du voyage :
La première chose qu'il faut remarquer est que c'est un élément defaultSelectedValue
qui opérera en mode ajout comme en mode consultation/modification. Ceci gràce à la
caractéristique dependentOfMainSelectQueryBuilder='no' de notre champ : le champ
"n'appartient plus" à la fiche et prendra systématiquement sa valeur par défaut.
De plus, la requête qui fournira cette valeur par défaut sera inopérante lorsque la fiche sera
ouverte en mode ajout : stuckWhenNoFilter='yes'. Ceci signifie qu'on ne sélectionnera pas
de Continent lors de l'ajout d'un voyage. Cette requête ne sert qu'à retrouver le Continent du
Pays d'un Voyage, lorsque la fiche de ce dernier est ouverte en mode consultation/modification.
Le castFilter définit attend comme filtre une valeur de clef primaire de la table
Voyage, ce qui est nécessaire puisque l'on est dans une fiche (un cardForm) Voyage.
La valeur renvoyée par la requête est une valeur de clef étrangère fk_tblPays_tblContinent,
c'est à dire une clef primaire de Voyage.
La clause from assure la jointure entre la table dont on sélectionne la valeur (tblPays) et la
table qui fournit le filtre (tblVoyage).
Un peu compliqué, mais on y arrive ;)
Limitation
Attention ! Une limitation du moteur Melba oblige à déclarer le champ qui pilote (ie.
le champ nommé) avant le champ dépendant.
Top
© Copyright 2003 Sashipa-Melba Team.
Ce document de la technologie Sashipa-Melba est
sous licence GNU FDL Vous
pouvez le copier et modifier librement les copies tant que cette mention apparaît clairement.
|