query - subconsultas en jpa
JPA 2.0, API de criterios, subconsultas, en expresiones (2)
Intenté escribir una declaración de consulta con una subconsulta y una expresión IN
muchas veces. Pero nunca he tenido éxito.
Siempre obtengo la excepción, "Error de sintaxis cerca de la palabra clave ''IN''", la instrucción de consulta se compilaba así,
SELECT t0.ID, t0.NAME
FROM EMPLOYEE t0
WHERE IN (SELECT ?
FROM PROJECT t2, EMPLOYEE t1
WHERE ((t2.NAME = ?) AND (t1.ID = t2.project)))
Sé la palabra antes de ''IN'' perder.
¿Alguna vez has escrito una consulta? ¿Cualquier sugerencia?
A continuación se muestra el pseudocódigo para usar la subconsulta utilizando la API de 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();
También definitivamente necesita algunas modificaciones ya que he intentado mapearlo de acuerdo con su consulta. Aquí hay un enlace http://www.ibm.com/developerworks/java/library/j-typesafejpa/ que explica muy bien el concepto.
Resurrección tardía.
Su consulta parece muy similar a la de la página 259 del libro Pro JPA 2: Mastering the Java Persistence API , que en JPQL lee:
SELECT e
FROM Employee e
WHERE e IN (SELECT emp
FROM Project p JOIN p.employees emp
WHERE p.name = :project)
Utilizando la base de datos EclipseLink + H2, no pude obtener el JPQL del libro ni los criterios respectivos funcionando. Para este problema en particular, he encontrado que si hace referencia al ID directamente en lugar de dejar que el proveedor de persistencia lo resuelva, todo funciona como se espera:
SELECT e
FROM Employee e
WHERE e.id IN (SELECT emp.id
FROM Project p JOIN p.employees emp
WHERE p.name = :project)
Finalmente, para responder a su pregunta, aquí hay una consulta de criterios de tipo fuertemente formulados que funciona:
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();