J'ai essayé d'écrire une instruction de requête avec une sous-requête et une expression IN
plusieurs fois. Mais je n'ai jamais réussi.
Je reçois toujours l'exception, "Erreur de syntaxe près du mot clé 'IN'", l'instruction de requête était construite 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 la Parole avant 'IN' perdre.
Avez-vous déjà écrit une telle requête? Toute suggestion?
Vous trouverez ci-dessous le pseudo-code permettant d'utiliser une sous-requête à l'aide de l'API Criteria.
CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();
CriteriaQuery<Object> criteriaQuery = criteriaBuilder.createQuery();
Root<EMPLOYEE> from = criteriaQuery.from(EMPLOYEE.class);
Path<Object> path = from.get("compare_field"); // field to map with sub-query
from.fetch("name");
from.fetch("id");
CriteriaQuery<Object> select = criteriaQuery.select(from);
Subquery<PROJECT> 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<Object> typedQuery = entityManager.createQuery(select);
List<Object> resultList = typedQuery.getResultList();
En outre, il doit absolument être modifié car j'ai essayé de le mapper 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îtriser l’API de persistance Java , qui se lit comme suit en JPQL:
SELECT e
FROM Employee e
WHERE e IN (SELECT emp
FROM Project p JOIN p.employees emp
WHERE p.name = :project)
En utilisant la base de données EclipseLink + H2, je n’ai pas réussi à obtenir le fonctionnement correct de JPQL ni des critères correspondants. Pour ce problème particulier, j'ai constaté que si vous référencez directement l'id au lieu de laisser le fournisseur de persistance le déterminer, tout se passe 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, afin de répondre à votre question, voici une requête de critère équivalente fortement typée qui fonctionne:
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<Employee> c = cb.createQuery(Employee.class);
Root<Employee> emp = c.from(Employee.class);
Subquery<Integer> sq = c.subquery(Integer.class);
Root<Project> project = sq.from(Project.class);
Join<Project, Employee> sqEmp = project.join(Project_.employees);
sq.select(sqEmp.get(Employee_.id)).where(
cb.equal(project.get(Project_.name),
cb.parameter(String.class, "project")));
c.select(emp).where(
cb.in(emp.get(Employee_.id)).value(sq));
TypedQuery<Employee> q = em.createQuery(c);
q.setParameter("project", projectName); // projectName is a String
List<Employee> employees = q.getResultList();
CriteriaBuilder criteriaBuilder = em.getCriteriaBuilder();
CriteriaQuery<Employee> criteriaQuery = criteriaBuilder.createQuery(Employee.class);
Root<Employee> empleoyeeRoot = criteriaQuery.from(Employee.class);
Subquery<Project> projectSubquery = criteriaQuery.subquery(Project.class);
Root<Project> projectRoot = projectSubquery.from(Project.class);
projectSubquery.select(projectRoot);
Expression<String> stringExpression = empleoyeeRoot.get(Employee_.ID);
Predicate predicateIn = stringExpression.in(projectSubquery);
criteriaQuery.select(criteriaBuilder.count(empleoyeeRoot)).where(predicateIn);