API JPA 2.0, Critères, Sous-requêtes, Expressions

J’ai essayé d’écrire une requête avec une sous-requête et une expression IN plusieurs fois. Mais je n’ai jamais réussi.

J’ai toujours l’exception, “Erreur de syntaxe près du mot clé ‘IN'”, l’instruction de requête a été générée comme ceci,

 SELECT t0.ID, t0.NAME FROM EMPLOYEE t0 WHERE IN (SELECT ? FROM PROJECT t2, EMPLOYEE t1 WHERE ((t2.NAME = ?) AND (t1.ID = t2.project))) 

Je connais le mot avant “IN” perdre.

Avez-vous déjà écrit une telle requête? Toute suggestion?

Vous trouverez ci-dessous le pseudo-code pour utiliser la sous-requête en utilisant l’API Criteria.

 CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder(); CriteriaQuery criteriaQuery = criteriaBuilder.createQuery(); Root from = criteriaQuery.from(EMPLOYEE.class); Path path = from.get("compare_field"); // field to map with sub-query from.fetch("name"); from.fetch("id"); CriteriaQuery select = criteriaQuery.select(from); Subquery subquery = criteriaQuery.subquery(PROJECT.class); Root fromProject = subquery.from(PROJECT.class); subquery.select(fromProject.get("requiredColumnName")); // field to map with main-query subquery.where(criteriaBuilder.and(criteriaBuilder.equal("name",name_value),criteriaBuilder.equal("id",id_value))); select.where(criteriaBuilder.in(path).value(subquery)); TypedQuery typedQuery = entityManager.createQuery(select); List resultList = typedQuery.getResultList(); 

En outre, il a certainement besoin d’être modifié car j’ai essayé de le cartographier en fonction de votre requête. Voici un lien http://www.ibm.com/developerworks/java/library/j-typesafejpa/ qui explique bien le concept.

Résurrection tardive

Votre requête semble très similaire à celle de la page 259 du livre Pro JPA 2: Maîsortingser l’API Java Persistence , qui, dans JPQL, indique:

 SELECT e FROM Employee e WHERE e IN (SELECT emp FROM Project p JOIN p.employees emp WHERE p.name = :project) 

En utilisant la firebase database EclipseLink + H2, je ne pouvais obtenir ni le fichier JPQL du livre ni les critères correspondants. Pour ce problème particulier, j’ai constaté que si vous référencez l’ID directement au lieu de laisser le fournisseur de persistance le découvrir, tout fonctionne comme prévu:

 SELECT e FROM Employee e WHERE e.id IN (SELECT emp.id FROM Project p JOIN p.employees emp WHERE p.name = :project) 

Enfin, pour répondre à votre question, voici une requête équivalente de critères fortement typés qui fonctionne:

 CriteriaBuilder cb = em.getCriteriaBuilder(); CriteriaQuery c = cb.createQuery(Employee.class); Root emp = c.from(Employee.class); Subquery sq = c.subquery(Integer.class); Root project = sq.from(Project.class); Join sqEmp = project.join(Project_.employees); sq.select(sqEmp.get(Employee_.id)).where( cb.equal(project.get(Project_.name), cb.parameter(Ssortingng.class, "project"))); c.select(emp).where( cb.in(emp.get(Employee_.id)).value(sq)); TypedQuery q = em.createQuery(c); q.setParameter("project", projectName); // projectName is a Ssortingng List employees = q.getResultList(); 
 CriteriaBuilder criteriaBuilder = em.getCriteriaBuilder(); CriteriaQuery criteriaQuery = criteriaBuilder.createQuery(Employee.class); Root empleoyeeRoot = criteriaQuery.from(Employee.class); Subquery projectSubquery = criteriaQuery.subquery(Project.class); Root projectRoot = projectSubquery.from(Project.class); projectSubquery.select(projectRoot); Expression ssortingngExpression = empleoyeeRoot.get(Employee_.ID); Predicate predicateIn = ssortingngExpression.in(projectSubquery); criteriaQuery.select(criteriaBuilder.count(empleoyeeRoot)).where(predicateIn);