Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

spring-data subquery within a Specification

Spring-data, Oliver Gierke's excellent library, has something called a Specification (org.springframework.data.jpa.domain.Specification). With it you can generate several predicates to narrow your criteria for searching.

Can someone provide an example of using a Subquery from within a Specification?

I have an object graph and the search criteria can get pretty hairy. I would like to use a Specification to help with the narrowing of the search, but I need to use a Subquery to see if some of the sub-elements (within a collection) in the object graph meet the needs of my search.

Thanks in advance.

like image 857
John Kroubalkian Avatar asked Aug 21 '12 19:08

John Kroubalkian


People also ask

Can we use subquery in JPA query?

JPA 2.0 supports subqueries in WHERE and HAVING clauses. In those they can be used in many types of expressions, including EXISTS and IN.

How do you add subquery criteria?

In the first step, I instantiate a CriteriaQuery which returns Author entities. Then I call the subquery method on the CriteriaQuery to create a subquery that counts the Books written by the Author which is selected by the outer query. As you can see, I define the subquery in the same way as I create a CriteriaQuery.

How does Spring data work internally?

Internally, Spring generates a JPQL query based on the method name, sets the provided method parameters as bind parameter values, executes the query and returns the result.

What is Querydsl in spring?

Querydsl is a framework that enables the construction of statically typed SQL-like queries through its fluent API. Spring Data modules offer integration with Querydsl through QuerydslPredicateExecutor .


1 Answers

String projectName = "project1";
List<Employee> result = employeeRepository.findAll(
    new Specification<Employee>() {
        @Override
        public Predicate toPredicate(Root<Employee> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
            Subquery<Employee> sq = query.subquery(Employee.class);
            Root<Project> project = sq.from(Project.class);
            Join<Project, Employee> sqEmp = project.join("employees");
            sq.select(sqEmp).where(cb.equal(project.get("name"),
                    cb.parameter(String.class, projectName)));
            return cb.in(root).value(sq);
        }
    }
);

is the equivalent of the following jpql query:

SELECT e FROM Employee e WHERE e IN (
    SELECT emp FROM Project p JOIN p.employees emp WHERE p.name = :projectName
)
like image 85
Pieter Avatar answered Oct 22 '22 02:10

Pieter