Basically, there are two ways to specify a projection term (or just a selection expression) on the CriteriaQuery<T> interface, in which the query result:
CriteriaQuery<T> select(Selection<? extends T> selection); CriteriaQuery<T> multiselect(Selection<?>... selections);
The commonly used projection term is the candidate class ( Address in your examples) of the query itself. It may be implicit, as in your first example.
The query from the Address object in your first example does not explicitly indicate its projection term, and it is similar to explicitly choosing the candidate class itself in this case.
The alleged permanent candidate object as the only projection term is implied.
If there is something other than the persistent candidate for the predicted query result, several other constructions are available for generating the query result. These designs are available in the CriteriaBuilder interface.
Methods for generating the query result:
CompoundSelection<Y> construct(Class<Y> result, Selection<?>... terms); CompoundSelection<Object[]> array(Selection<?>... terms); CompoundSelection<Tuple> tuple(Selection<?>... terms);
For completeness only, I will try to demonstrate each of them, in turn, with a simple example for each of them.
Formation of the query result in class instances (not a constant object) on construct() :
The construct() method creates an instance of this class argument and calls the constructor (mutable object) with values ββfrom the input selection conditions. These arguments to the constructor of a mutable object (not even an entity, a simple Java class) must correspond, for example, to the number, order, and type (data type) with values ββthat match the input selection conditions.
CriteriaQuery<EmployeeDetails> q = cb.createQuery(EmployeeDetails.class); Root<Employee> root = q.from(Employee.class); q.select(cb.construct(EmployeeDetails.class, root.get(Employee_.empName), root.get(Employee_.salary));
EmployeeDetails in this case is a simple Java class - a mutable entity that has a constructor that takes two parameters of type String (for empName ) and BigDecimal (for salary ).
The request returns List<EmployeeDetails> - a mutable object from the selected Employee - a persistent object.
Depending on the number of rows returned, the query may also return EmployeeDetails using the getSingleResult() method, for example.
Several selection elements can also be combined into a composite selection term that represents Object[] or Tuple , as shown below.
Formation of the query result in Object[] :
CriteriaQuery<Object[]> q = cb.createQuery(Object[].class); Root<Employee> root = q.from(Employee.class); q.select(cb.array(root.get(Employee_.empName), root.get(Employee_.salary)); List<Object[]> list = entityManager.createQuery(q).getResultList();
As you can see, the query returns a List<Object[]> . Each item in this list contains a 0-based array of Object - Object[] .
Formation of the query result in Tuple :
CriteriaQuery<Tuple> q = cb.createTupleQuery(); Root<Employee> root = q.from(Employee.class); Selection<String> empName = root.get(Employee_.empName).alias("empName"); q.select(cb.tuple(empName, root.get(Employee_.salary).alias("salary"); List<Tuple> list = entityManager.createQuery(q).getResultList(); String employeeName = list.get(0).get("empName");
The query returns a List<Tuple> . Values ββstored in Tuple are accessible through an integer index based on 0, using the alias TupleElement or directly through TupleElement .
CriteriaBuilder#createTupleQuery() similar to CriteriaBuilder#createQuery(Tuple.class) .
Using multiselect() to interpret terms based on the type of result:
Input terms are automatically interpreted using the multiselect() method based on the CriteriaQuery result type to automatically obtain the result form β the type of the CriteriaQuery return value. For example, the very first example in this answer can be rewritten with multiselect() as follows.
CriteriaQuery<EmployeeDetails> q = cb.createQuery(EmployeeDetails.class); Root<Employee> root = q.from(Employee.class); q.multiselect(root.get(Employee_.empName), root.get(Employee_.salary));
Because the result type is EmployeeDetails , the multiselect() method interprets its projection terms as arguments to the EmployeeDetails constructor.
Note that a constructor such as cb.construct(EmployeeDetails.class, root.get(Employee_.empName), root.get(Employee_.salary) used in the first example should not be used in the previous example using multiselect() , which automatically interprets its projection run arguments based on the returned query type and calls the corresponding constructor in the result class - EmployeeDetails .
If the request were to be specified to return a Tuple (or a list of Tuple s), the multiselect() method with the same arguments would create Tuple instances, as shown below.
CriteriaQuery<Tuple> q = cb.createTupleQuery(); Root<Employee> root = q.from(Employee.class); q.multiselect(root.get(Employee_.empName), root.get(Employee_.salary));
There is no need to mention, but the same thing can be rewritten to return Object[] (or a list of Object[] s).
CriteriaQuery<Object[]> q = cb.createQuery(Object[].class); Root<Employee> root = q.from(Employee.class); q.multiselect(root.get(Employee_.empName), root.get(Employee_.salary));
In both cases, the muliselect() method automatically interprets the terms of the projection of the argument based on the return type of the request, as mentioned earlier, which is equal to Tuple and Object[] respectively.
It should also be noted that EcliseLink has a bug that still needs to be fixed when extracting a single Boolean term in this way using multiselect() , as shown in this question .
Depending on the different JPA providers, the behavior of the multiselect() method becomes more interesting with Object as the result,
- If the
multiselect() method is used with a single selection term, the return type is the selected term. - If the
multiselect() method, however, contains more than one input term / sample member / projection member, the result type is Object[] .
I'm not quite sure about the different providers, but the selection conditions specified in the multiselect() method may not be an array or collection (or a complex term term). The only composite members that can be resolved as arguments to multiselect() are those created using the construct() method, which essentially represents a single element in turn.
In addition to the above constructions, using CriteriaQuery#select(Selection<? extends T> selection) quite common when using scalar / group / aggregate / single-valued functions such as count() , max() , min() , etc. and subqueries. The use of subqueries is excluded from this answer for brevity.
A Selection determines what is selected by the query. The selection can be any object expression, attribute expression, function, subselect, constructor, or aggregation function. An alias can be defined for Selection using the alias API ().
CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder(); // Count the total employees CriteriaQuery criteriaQuery = criteriaBuilder.createQuery(); Root employee = criteriaQuery.from(Employee.class); criteriaQuery.select(criteriaBuilder.count(employee)); //<------ Query query = entityManager.createQuery(criteriaQuery); Long result = query.getSingleResult(); // Maximum salary CriteriaQuery criteriaQuery = criteriaBuilder.createQuery(); Root employee = criteriaQuery.from(Employee.class); criteriaQuery.select(criteriaBuilder.max(employee.get("salary")); //<------ Query query = entityManager.createQuery(criteriaQuery); Long result = query.getSingleResult();
http://en.wikibooks.org/wiki/Java_Persistence/Criteria#Selection