Utilisez des annotations pureQuery dans un ensemble de
beans imbriqués afin de créer des ensembles de beans qui renvoient des données issues de requêtes SQL contenant des jointures de table. pureQuery Runtime génère l'implémentation
de l'ensemble des beans imbriqués.
Cette implémentation
se base sur des jointures de table dans les instructions SQL et les annotations pureQuery
ajoutées aux beans.
Créez un ensemble de beans imbriqués définissant la
structure hiérarchique des données à renvoyer. Lorsque vous spécifiez
une annotation @JoinPoint dans la propriété d'un bean correspondant
à la colonne d'un objet ResultSet, pureQuery Runtime génère l'implémentation adéquate. pureQuery Runtime analyse la structure hiérarchique du bean de niveau supérieur, qui correspond au bean renvoyé après avoir terminé le traitement de l'objet ResultSet et des beans imbriqués. Seuls ces
beans ou listes de beans mis à jour par la colonne d'un objet ResultSet
et disposant d'une annotation @JoinPoint sont générés et complétés.
Tout bean ou liste de beans qui n'est pas complété(e) par la colonne d'un objet
ResultSet ou qui ne dispose d'aucune annotation @JoinPoint affiche la valeur
null ou une valeur d'initialisation du constructeur de beans.
Cette rubrique
contient les sections suivantes :
Exemple de beans imbriqués
Voici un exemple
montrant deux beans, le bean de niveau supérieur correspond à un bean Department
et les beans enfant correspondent à une liste des beans Employee.
Cet exemple utilise
la requête SQL suivante avec une jointure entre les tables DEPARTMENT
et EMPLOYEE. La requête utilise un paramètre, le numéro de service, et renvoie
tous les employés appartenant à ce service :
Select D.DEPTNO, D.DEPTNAME, D.MGRNO, D.ADMRDEPT, E.EMPNO, E.FIRSTNME, E.MIDINIT,
E.LASTNAME, E.JOB, E.SEX, E.BIRTHDATE, E.SALARY
from (DEPARTMENT AS D LEFT JOIN EMPLOYEE AS E ON D.DEPTNO=E.WORKDEPT)
WHERE D.DEPTNO=? ORDER BY D.DEPTNO, E.LASTNAME
La méthode de l'interface DAO suivante spécifie la requête
SQL :
@Select(sql = "Select D.DEPTNO, D.DEPTNAME, D.MGRNO, D.ADMRDEPT, E.EMPNO,
E.FIRSTNME, E.MIDINIT, E.LASTNAME, E.JOB, E.SEX, E.BIRTHDATE, E.SALARY
from (DEPARTMENT AS D LEFT JOIN EMPLOYEE AS E ON D.DEPTNO=E.WORKDEPT)
WHERE D.DEPTNO=? ORDER BY D.DEPTNO, E.LASTNAME")
public Department joinTest (String deptNo);
Les deux
beans suivants ont été développés pour la requête SQL. Le bean Department
est un bean de niveau supérieur qui est renvoyé après avoir terminé le traitement de l'ensemble des résultats. Le bean Department correspond au bean parent de la liste des beans deptEmployees. La liste des beans deptEmployees correspond à un ensemble de beans enfant. La colonne d'identité, qui correspond à la propriété d'un bean affichant l'annotation @Id,
est deptNo.
@Table(name = "DEPARTMENT")
public class Department
{
@Id
@GeneratedKey
public String deptNo; // this is the ID of the bean and its value is generated by the database
public String deptName;
public String mgrNo;
public String admrDept;
@JoinPoint(@JoinColumn(name = "EMPNO", table = "EMPLOYEE", propertyName = "empNo"))
public List<Employee> deptEmployees;
}
Les données renvoyées par la liste des beans deptEmployees
est définie par la classe Employee.
@Table(name = "EMPLOYEE")
public class Employee
{
@Id
@GeneratedKey
public String empNo; // this is the ID of the bean and its value is generated by the database
public String firstNme;
public String midInit;
public String lastName;
public String workDept;
public String job;
public String sex;
public java.sql.Date birthdate;
public String salary;
}
En fonction de la requête SQL et des beans, pureQuery
Runtime génère un code d'implémentation pour les beans.
Les objets Java renvoyés correspondent à un bean Department contenant une liste java.util.list de 11 beans deptEmployees.
Le résultat formaté est généré suite à l'appel de la méthode
joinTest("D11").
Les quatre premières colonnes correspondent aux données issues du bean Department, les autres colonnes
de données d'employés sont issues des beans deptEmployees :
dept admr mid
No deptName mgrNo Dept empNo firstNme Init lastName job sex birthdate salary
D11 MANUFACTURING SYSTEMS 000060 D01 000150 BRUCE ADAMSON DESIGNER M 1977-05-17 55280.00
000200 DAVID BROWN DESIGNER M 1971-05-29 57740.00
200220 REBA K JOHN DESIGNER F 1978-03-19 69840.00
000210 WILLIAM T JONES DESIGNER M 2003-02-23 68270.00
000220 JENNIFER K LUTZ DESIGNER F 1978-03-19 49840.00
000160 ELIZABETH R PIANKA DESIGNER F 1980-04-12 62250.00
000180 MARILYN S SCOUTTEN DESIGNER F 1979-02-21 51340.00
000060 IRVING F STERN MANAGER M 1975-07-07 72250.00
000190 JAMES H WALKER DESIGNER M 1982-06-25 50450.00
200170 KIYOSHI YAMAMOTO DESIGNER M 1981-01-05 64680.00
000170 MASATOSHI J YOSHIMURA DESIGNER M 1981-01-05 44680.00
Types de beans dans un ensemble de beans imbriqués
Lorsque vous créez un ensemble de beans imbriqués pour les requêtes SQL contenant des jointures de table,
vous créez les types de beans suivants :
- Bean de niveau supérieur
- Le bean de niveau supérieur est un bean correspondant à la valeur de retour de la
méthode ou de l'interface API intégrée. Ce bean doit disposer au moins d'une annotation @Id
lorsqu'il est utilisé avec les annotations pureQuery dans un ensemble de
beans imbriqués. En tant que bean parent, il doit aussi contenir au moins une
annotation @JoinPoint. Ce bean peut être un bean parent ou enfant. Dans certains
cas, un bean peut être à la fois un bean parent et enfant dans la même
structure d'imbrication.
- Bean parent
- Un bean parent doit contenir au moins une annotation @JoinPoint
qui référence un bean ou une liste de beans, et des beans enfant. Aucune annotation @Id
n'est obligatoire dans un bean parent à moins qu'il s'agisse d'un bean de niveau supérieur. Si un bean
parent (par exemple : BeanB) ne contient aucune annotation @Id,
il doit aussi être un bean enfant. Le bean parent de BeanB, BeanA, doit contenir
des annotations @JoinColumn dans une annotation @JoinPoint.
Les annotations @JoinColumn figurant dans BeanA indiquent des colonnes d'identité pour son bean
enfant, BeanB.
- Bean enfant
- Un bean enfant est référencé par son bean parent avec une
annotation @JoinPoint. Un bean enfant n'a pas besoin de contenir une annotation @Id à moins qu'il s'agisse
également d'un bean de niveau supérieur. Si un bean enfant ne contient aucune
annotation @Id, alors son bean parent doit spécifier les colonnes d'identité du bean
avec une ou plusieurs annotations @JoinColumn figurant dans une
annotation @JoinPoint.
Colonnes d'identité dans un ensemble de beans imbriqués
Lors de la génération et du remplissage d'un ensemble de
beans imbriqués, pureQuery Runtime utilise l'annotation @JoinPoint dans la référence
au bean figurant dans le parent du bean ou une annotation @Id
dans le bean même. Les annotations définissent les colonnes d'identité qui lient
les beans enfant au bean parent. Par exemple, pureQuery Runtime
utilise des colonnes d'identité pour déterminer le moment auquel une liste de beans
doit être générée pour un bean parent.
Par exemple, une table EMPLOYEE peut contenir
plusieurs colonnes pouvant être des colonnes d'identité. Les colonnes qui peuvent être définies
comme colonne d'identité sont le matricule ou le numéro de sécurité sociale de l'employé. La colonne d'identité peut être la clé principale
de la table, mais pas nécessairement une clé de table. Plusieurs colonnes
peuvent être combinées dans une clé composée, tout comme une clé composée peut être créée
sur une table de base de données. Le nom d'une colonne d'identité de la table EMPLOYEE peut refléter un mauvais choix, étant donné que les employés peuvent porter le même nom.
pureQuery
Runtime utilise les informations de la colonne d'identité et d'autres informations relatives aux beans
lors du traitement de l'objet ResultSet. Pour une requête SQL contenant des jointures de
table, les données de l'objet ResultSet peuvent rendre plus difficile le mappage de ces données dans une structure de beans hiérarchique. Les caractéristiques suivantes
peuvent causer des problèmes au cours du traitement :
- Les données peuvent ne pas être triées.
- L'ordre des données dans les tables de base de données peut être
conservé.
- Les données figurant dans ResultSet sont dupliquées. Ceci se produit lorsque les données
contiennent des relations un à plusieurs dans la base de données. Par exemple, un service
se compose de nombreux employés. Un ResultSet peut contenir des données issues d'une jointure
entre une table Department et une table Employee. Les informations sur le service
sont dupliquées pour chaque employé de ce service.
pureQuery Runtime vérifie que les beans sont renseignés avec l'ensemble de données correctes et dans l'ordre adéquat. Par exemple, les données ResultSet peuvent ne pas être triées pour effectuer un mappage exact vers la structure de beans imbriqués. pureQuery Runtime peut traiter des données ResultSet appartenant
aux beans qui ont été créés antérieurement lors du traitement des données
ResultSet et renseigner les beans avec les données adéquates dans l'ordre correct.
Règles de création d'ensembles de beans imbriqués
Vous pouvez créer un ensemble de beans imbriqués renvoyant des résultats issus d'instructions SQL avec des prédicats de jointure complexes en créant une structure d'imbrication plus complexe avec les annotations adéquates. Pour créer un ensemble de beans renvoyant des résultats corrects, les règles suivantes doivent être suivies. La requête SQL ou les beans peuvent exiger des modifications afin de générer un ensemble de beans utiles.
- Le nom de chaque colonne de l'objet ResultSet doit effectuer un mappage vers
une seule propriété du bean parent ou d'un bean enfant.
Remarque : Si plusieurs colonnes
effectuent un mappage vers une propriété donnée et que les colonnes renvoient toujours
les mêmes données, ce mappage n'est pas problématique. Des problèmes peuvent apparaître
si une ou plusieurs de ces colonnes affichent une valeur null. Par exemple, une colonne peut
renvoyer une valeur null suite à une requête SQL contenant une jointure de table. Cette requête
peuvent contenir une clause WHERE ou ON qui ne trouve aucune clé correspondante
entre les deux tables.
Ce problème peut être résolu en spécifiant
des alias dans la requête SQL. Les annotations @Column, @Table ou @JoinColumn peuvent aussi
être spécifiées avec le nom de table dans les propriétés des beans
disposant de plusieurs colonnes.
- Si la structure des beans imbriqués contient plusieurs fois le même bean, toutes les références à ce bean seront ignorées après la première
instance. Le fait d'utiliser la première instance seule empêche d'éventuelles récursivités
infinies dans le traitement de l'ensemble de beans imbriqués par pureQuery Runtime. Utilisez un élément facultatif @JoinPoint
columnPrefix ou une sous-classe du bean d'origine
et des alias de colonnes dans la requête SQL ou des annotations @JoinPoint
ou @JoinColumn pour créer plusieurs beans semblables.
- L'élément requis @JoinColumn name doit correspondre
au nom de la propriété de base du bean enfant. Sinon, l'élément facultatif
propertyName doit être spécifié
avec le nom de la propriété de base correspondante du bean enfant.
Le nom de la propriété de base correspond au nom de la propriété d'un bean sans annotation existante qui modifie son mappage vers l'objet ResultSet. Pour une zone,
le nom de la propriété de base correspond au nom de la variable Java. Pour une méthode get, set ou is, il s'agit du nom de la méthode sans le préfixe get, set ou is et le premier caractère défini en minuscules. Dans les exemples suivants, l'étiquette WORKDEPT de la colonne ResultSet
n'est pas sensible à la casse.
Dans l'exemple suivant de la méthode get,
le nom de la propriété de base workDepartment est sensible à la casse.
@Column(name = "WORKDEPT")
public String getWorkDepartment ();
Une
annotation @JoinColumn peut être spécifiée dans une annotation @JoinPoint sur un bean
ou une liste de beans. Dans ce cas, les éléments name et table spécifiés écrasent le libellé de colonne et le nom de table facultatif définis
dans les annotations @Id du bean enfant, y compris toute annotation @Column
associée qui est spécifiée.
Un bean enfant peut disposer de plusieurs
annotations @Id. Dans ce cas, l'élément requis
name de l'annotation @JoinColumn doit correspondre au nom de la propriété de base
du bean enfant. Si les noms ne correspondent pas, alors l'élément facultatif propertyName doit être spécifié
avec le nom de la propriété de base correspondante du bean enfant.
Si vous modifiez l'exemple précédent afin qu'un alias EMPNO de la requête SQL affiche EMPNUM, l'élément
propertyName n'est pas requis dans une annotation @JoinColumn. Le bean enfant ne dispose que d'une seule annotation @Id et pureQuery Runtime détermine la propriété devant faire l'objet d'un mappage. Il est conseillé de modifier l'annotation @JoinPoint suivante du bean Department :
@JoinPoint(@JoinColumn(name = "EMPNO", table = "EMPLOYEE", propertyName = "empNo"))
public List<Employee> deptEmployees;
L'annotation @JoinPoint peut être spécifiée comme suit :
@JoinPoint(@JoinColumn(name = "EMPNUM", table = "EMPLOYEE", propertyName = "empNo"))
public List<Employee> deptEmployees;
Si vous voulez
changer la colonne d'identité empNo du bean enfant Employee pour la nommer workDept, spécifiez l'élément
PropertyName comme suit :
@JoinPoint(@JoinColumn(name = "WORKDEPT", table = "EMPLOYEE", propertyName = "workDept"))
public List<Employee> deptEmployees;
- L'annotation @Table est utilisée au niveau de la classe. L'annotation
spécifie un nom de table par défaut à ajouter à toutes les propriétés qui n'indiquent
aucun nom de table. Le nom de la table peut être écrasé pour spécifier
une propriété correspondant à n'importe quel nom de table.
- Les beans enfant n'exigent aucune annotation @Id pour être considérés
comme faisant partie de l'ensemble de beans imbriqués. L'annotation @JoinPoint
peut spécifier les colonnes d'identité du bean enfant. La spécification
de colonnes d'identité à l'aide de l'annotation @Id concerne uniquement ce bean parent
dans cet appel.
Un bean enfant doit être un bean unique ou une liste de
beans et doit afficher l'annotation @JoinPoint. Cette dernière doit se trouver
dans la propriété du bean parent qui définit
le bean enfant ou la liste de beans.
- Chaque colonne de l'objet ResultSet doit uniquement effectuer un mappage vers les propriétés
du bean parent et les beans enfant qui sont corrects.
Un exemple
de ce type de mappage est une table DEPARTMENT qui dispose d'une colonne DEPTNO correspondant
à une clé principale et une table PROJECT qui dispose aussi d'une colonne DEPTNO.
La colonne DEPTNO de la table PROJECT est une clé externe de la table DEPARTMENT. La correspondance par défaut entre les colonnes de l'objet ResultSet et les propriétés
est le libellé de la colonne. Dans cet exemple, une jointure des tables DEPARTMENT
et PROJECT peut générer deux colonnes avec le libellé de colonne
DEPTNO. Si la structure du bean parent et enfant exige que ces colonnes
affichent des informations différentes, vous pouvez ajouter des annotations aux beans.
Ces annotations peuvent utiliser un nom de table afin de rendre les colonnes uniques. Vous pouvez aussi
modifier l'instruction SQL en ajoutant un alias pour créer un libellé de colonne unique. Toutefois, il n'est pas rare pour les requêtes SQL disposant d'une jointure de renvoyer uniquement une colonne lorsque plusieurs colonnes contiennent des données identiques. Dans ce cas, elles sont valides pour une colonne pour la mise à jour de plusieurs propriétés.
Grâce aux méthodes de type DAO (Data Access Object), des avertissements issus de plusieurs propriétés en cours de mise à jour s'affichent dans la même colonne à partir de l'objet ResultSet de la manière suivante :
- Un avertissement s'affiche en décrivant les méthodes générées utilisant
la même colonne. Cet avertissement s'affiche une fois l'implémentation générée
si vous utilisez IBM® Data
Studio. Cet avertissement figure également dans le fichier journal du générateur s'il
existe et le niveau de trace est défini sur java.util.logging.Level.WARNING
ou à un emplacement plus précis.
- Le générateur pureQuery crée un bloc de commentaires au-dessus du
ResultHandler de bean imbriqué généré. Le commentaire affiche les gestionnaires générés
qui utilisent la colonne ResultSet. Il affiche également les colonnes ResultSet qui ne sont jamais
utilisées.
Avec ce type de méthode intégrée, des avertissements issus de plusieurs propriétés en cours de mise à jour par cette même colonne ResultSet s'affichent. Ces avertissements sont
consignés dans le fichier journal pureQuery Runtime s'il existe et le niveau de
trace est défini sur java.util.logging.Level.WARNING ou à un emplacement plus précis.
- Une annotation @JoinPoint est requise chaque fois qu'un bean enfant est joint à un
bean parent. Une annotation @JoinColumn doit être spécifiée dans
l'annotation @JoinPoint, sauf lorsque l'une des instructions suivante est vraie :
- Le bean enfant ou la liste de beans contient une ou plusieurs annotations @Id
qui définissent de façon exhaustive les colonnes d'identité du bean enfant.
- Les propriétés de la colonne d'identité du bean enfant (quel que soit le libellé de colonne et le nom de table facultatifs) indiquent de façon correcte les colonnes de l'instruction SQL
exécutées pour créer l'objet ResultSet. Dans ce cas, vous pouvez spécifier uniquement
l'annotation @JoinPoint sans aucun élément.
Traitement de l'exécution d'un bean imbriqué
Les étapes suivantes décrivent comment pureQuery Runtime traite un ensemble de beans imbriqués
lors de la génération d'objets avec les données issues d'un objet ResultSet.
- L'analyse syntaxique commence par le bean renvoyé, c'est-à-dire le bean
parent de niveau supérieur. Chaque propriété du bean est examinée afin de déterminer si cette
propriété est mise à jour par l'objet ResultSet. Si une propriété est mise à jour
et dispose d'une annotation @JoinPoint, alors cette propriété est examinée
pour déterminer si elle référence un bean ou une liste de beans. Si la propriété
référence un bean ou une liste de beans, ce bean est ajouté à une liste
de beans enfant pour le bean parent. Toutes les propriétés figurant dans le bean parent
sont traitées avant que pureQuery Runtime ne traite un bean enfant ayant été trouvé. L'ordre d'examen des propriétés d'un bean n'est pas déterminant.
- Une fois que toutes les propriétés d'un bean parent ont été examinées,
la liste des beans enfant est vérifiée. Si elle contient un ou plusieurs beans enfant,
alors le premier bean de la liste est traité comme s'il s'agissait d'un bean parent.
- Après avoir trouvé le premier bean enfant dans le bean parent d'origine et créé une liste
de ses beans enfant, pureQuery Runtime traite
le bean enfant suivant du bean parent d'origine. S'il existe un autre bean, ce dernier est traité
comme dans l'étape précédente.
Tous les beans enfant du bean
parent d'origine sont traités avant de traiter n'importe quel bean enfant
pour déterminer s'ils contiennent des beans enfant.
pureQuery Runtime peut déterminer si une classe du bean enfant est traitée pour la première fois ou s'il existe des références récursives
dans les beans. Si l'analyse syntaxique pureQuery Runtime de la structure du bean imbriqué
détecte un bean ayant déjà été analysé, elle arrête l'analyse
syntaxique de ce bean enfant.
Remarque : Un bean parent contenant
deux ou plusieurs beans enfant identiques n'est pas pris en charge. Dans ce cas,
pureQuery Runtime place les informations dans un seul des
beans enfant. Vous pouvez indiquer une sous-classe avec des annotations de propriétés uniques
du bean enfant. Vous pouvez aussi utiliser l'élément columnPrefix
dans l'annotation @JoinPoint du bean parent pour chacune des classes en double.
Des références récursives à un bean affectent également la manière dont l'exécution de pureQuery
renseigne les propriétés des beans enfant. Seule la première instance
du bean est renseignée. Les références ultérieures à ce bean sont ignorées
à moins que la référence ne dispose d'une annotation @JoinColumn avec un autre élément columnPrefix défini. Etant donné que l'ordre de traitement des propriétés dans un bean unique n'est pas déterminant, il en est de même pour l'ordre de traitement des beans enfant. Toutefois, les beans enfant sont traités dans l'ordre du
niveau d'imbrication. Par exemple, un bean imbriqué
directement dans le bean parent est traité avant un bean au prochain niveau
d'imbrication.
Pour plus d'informations sur l'élément columnPrefix,
reportez-vous à la documentation relative à l'annotation @JoinPoint.