Résolution d'une requête JPA pour trouver la dernière entrée de la liste connectée
Question
La structure de classe suivante est donnée:
class Job
{
String description;
Collection<JobHistory> history;
}
class JobHistory
{
Date assignDate;
User jobOwner;
}
class JobOwner
{
String name;
String id;
}
Cette structure de classe est accessible sur la base de données via JPA. Dans la couche DAO, je peux écrire des requêtes en syntaxe JPA.
Le problème: je veux une liste avec les entrées Job
et JobHistory
pour un propriétaire donné avec un identifiant donné et qui est le dernier de la liste Jobhistory
du travail (ordonné par assignDate). Cela semble assez compliqué, peut-être plus simple: donnez-moi tous les travaux et JobHistory
où propriétaire spécifié est le propriétaire réel du travail.
Mise à jour: pour plus de clarté, je vais modifier légèrement les noms des classes.
class Job
{
String description;
Collection<JobOwnerHistory> history;
}
class JobOwnerHistory
{
Date assignDate;
User jobOwner;
}
class JobOwner
{
String name;
String id;
}
Chaque travail
a un historique de ses propriétaires trié par assignDate
. Le propriétaire actuel a reçu le dernier travail attribué (c'est-à-dire MAX (assignDate)
). Je souhaite trouver pour chaque travail l'entrée JobOwnerHistory
avec MAX (assignDate)
pour un utilisateur spécifique Utilisateur
.
La solution
Essayez:
SELECT j, j.history FROM Job j JOIN User u WHERE u.name = :name
Si je devais le faire dans EclipseLink, je le modifierais légèrement:
public List<Job> getAllJobsForUser(String username) {
List<Job> jobs = entityManager
.createQuery("SELECT j FROM Job j JOIN User u WHERE u.name = :name")
.setParameter("name", username)
.setHint(QueryHints.BATCH, "j.history")
.queryForList();
}
La différence? Dans la première version, vous renvoyez deux objets. Vous devez donc les récupérer à partir de tableaux ou de tableaux alors que dans la seconde, l'indicateur de requête ne charge que tous les historiques de travaux d'une relation (supposée) un-à-plusieurs. .
Je ne sais pas si Hibernate a un équivalent à cela. Toplink Essentials ne le fait pas. Mais c’est l’une de mes fonctionnalités préférées d’EclipseLink.
Oh, et évidemment vous pouvez (et devriez probablement) utiliser une requête nommée au lieu d’une requête ad hoc, comme je l’ai fait (car celles-ci peuvent être vérifiées lors de la construction).
Autres conseils
J'ai trouvé la réponse suivante pour la requête:
SELECT j, h FROM Job j JOIN j.history h JOIN h.jobOwner u
WHERE u.name = :name AND
(SELECT MAX(h2.assignDate) FROM Job j2 JOIN j2.history h2
WHERE h2 member of j.history) = h.assignDate
La partie la plus importante de la requête est la sous-sélection avec MAX (h2.assignDate)
car je souhaite obtenir le travail et la dernière entrée de l'historique propriétaire. .