diff --git a/documentation/manual/src/main/docbook/en-US/HIBERNATE_-_Relational_Persistence_for_Idiomatic_Java.ent b/documentation/manual/src/main/docbook/en-US/HIBERNATE_-_Relational_Persistence_for_Idiomatic_Java.ent index 84bf99c905..242a641093 100644 --- a/documentation/manual/src/main/docbook/en-US/HIBERNATE_-_Relational_Persistence_for_Idiomatic_Java.ent +++ b/documentation/manual/src/main/docbook/en-US/HIBERNATE_-_Relational_Persistence_for_Idiomatic_Java.ent @@ -1,5 +1,5 @@ - + diff --git a/entitymanager/src/main/docbook/en/modules/query_criteria.xml b/entitymanager/src/main/docbook/en/modules/query_criteria.xml index 46bea10c03..350b2c98e3 100644 --- a/entitymanager/src/main/docbook/en/modules/query_criteria.xml +++ b/entitymanager/src/main/docbook/en/modules/query_criteria.xml @@ -26,218 +26,532 @@ Criteria Queries - - - This chapter elaborates on the material discussed in - Chapter 6 Criteria API - ofJPA 2 Specification. - - - Criteria queries are a programmatic, type-safe way to express a query. They are type-safe in terms of using interfaces and classes to represent various structural parts of a query such as the query itself, or the select clause, or an order-by, etc. They can also be type-safe in terms of referencing attributes as we will see in a bit. Users of the older - Hibernate - org.hibernate.Criteria - query API will recognize + Hibernate org.hibernate.Criteria query API will recognize the general approach, though we believe the JPA API to be superior as it represents a clean - look at the lessons learned from that API. There are essentially 2 phases to performing - a criteria query: - - - - - Building the criteria instance - - - - - Executing the criteria instance - - - + look at the lessons learned from that API. + + Criteria queries are essentially an object graph, where each part of the graph represents an increasing + (as we navigate down this graph) more atomic part of query. The first step in performing a criteria query + is building this graph. The javax.persistence.criteria.CriteriaBuilder + interface is the first thing with which you need to become acquainted to begin using criteria queries. Its + role is that of a factory for all the individual pieces of the criteria. You obtain a + javax.persistence.criteria.CriteriaBuilder instance by calling the + getCriteriaBuilder method of the + javax.persistence.EntityManagerFactory + -
- Criteria query building + CriteriaBuilder builder = entityManagerFactory.getCriteriaBuilder(); + + + The next step is to obtain a javax.persistence.criteria.CriteriaQuery. + You do this by one of the 3 methods on javax.persistence.criteria.CriteriaBuilder + for this puropse. + + + createQuery(Class)]]> + createTupleQuery()]]> + createQuery()]]> + + + Each serves a different purpose depending on the expected type of the query results. + + + - Criteria queries are essentially an object graph, where each part of the graph - represents an increasing (as we navigate down this graph) more atomic part of - query. The first step in performing a criteria query is building this graph. + Chapter 6 Criteria API of the + already contains a decent amount of reference material + pertaining to the various parts of a criteria query. So rather than duplicate all that content here, + lets instead look at some of the more widely (anticipated) usages of the API. -
- CriteriaBuilder + + +
+ Typed criteria queries + createQuery(Class)]]> + + The type of the criteria query (aka the <T>) indicates the expected types in the + query result. This might be an entity, an Integer, or any other object. + + +
+ Selecting an entity - The - javax.persistence.criteria.CriteriaBuilder - interface is the - first thing with which you need to become acquainted to begin using criteria queries. Its role - is a factory for all the individual pieces of the criteria. You obtain a - javax.persistence.criteria.CriteriaBuilder - instance by calling - the - javax.persistence.EntityManagerFactory.getCriteriaBuilder - method: + This the most used form of query in Hibernate Query Language (HQL) and Hibernate Criteria Queries. + You have an entity and you want to select one or more of that entity based on some condition. - CriteriaBuilder builder = entityManagerFactory.getCriteriaBuilder(); + + Selecting the root entity + + + + + + + + + + criteria = builder.createQuery( Person.class ); +Root personRoot = criteria.from( Person.class ); +criteria.select( personRoot ); +criteria.where( builder.equal( personRoot.get( Person_.eyeColor ), "brown" ) ); +List people = em.createQuery( criteria ).getResultList(); +for ( Person person : people ) { ... }]]> + + + + + We use the form createQuery( Person.class ) + here because the expected returns are in fact Person entities as we see when we + begin processing the results. + + + + + personCriteria.select( personRoot ) here is completely + unneeded in this specific case because of the fact that personRoot + will be the implied selection since we have only a single root. It was done here only + for completeness of an example + + + + + Person_.eyeColor is an example of the static form of metamodel + reference. We will use that form exclusively in this chapter. + See (todo link to metamodel section once written). + + + +
-
- CriteriaQuery creation + +
+ Selecting a value - Once you have the - javax.persistence.criteria.CriteriaBuilder - reference - you can begin building the pieces of the criteria query. First, you will need a - javax.persistence.criteria.CriteriaQuery - instance. - javax.persistence.criteria.CriteriaBuilder - defines 3 methods - for obtaining a - javax.persistence.criteria.CriteriaQuery - instance: + The simplest form of selecting a value is selecting a particular attribute from an entity. But + this might also be an aggregation, a mathematical operation, etc. - - - createQuery(Class)]]> - - - createTupleQuery()]]> - - - createQuery()]]> - - - - Each serves a different purpose depending on the expected type of the query results. The type - is "carried forward" to the - javax.persistence.TypedQuery - we - create from this - javax.persistence.criteria.CriteriaQuery - as - we will see later inlater. - -
- Typed CriteriaQuery - - personCriteria = builder.createQuery(Person.class);]]> - - Basically this is saying to create a criteria where the results of this query will be of type - Person. Person might be an entity or it might not. The type could even be simple types like - java.lang.Integer,java.lang.String, etc. We - will discuss this topic in more detail in - - -
-
- Tuple CriteriaQuery - - personCriteria = builder.createTupleQuery();]]> - - personCriteria = builder.createQuery(Tuple.class);]]> - - These two forms are exactly the same. Both say to create a criteria where the results of this - query will be of typejavax.persistence.Tuple. The term tuple is - taken from mathematics, but its intent here is simply to mean a plurality; namely we are saying - that each query result will actually be multiple values, a projection. The - javax.persistence.Tuple - instance gives us typed access to these - multiple result values after the query has been executed. We will discuss accessing the query - results via a - javax.persistence.Tuple - in - . - -
-
- Untyped CriteriaQuery - - personCriteria = builder.createQuery();]]> - - personCriteria = builder.createQuery(Object.class);]]> - - These two forms are exactly the same. Both say to create a criteria where the results of this - query could be anything. Not generally recommended as you obviously lose the type safety. - -
+ + Selecting an attribute + + + + + + + + + criteria = builder.createQuery( Integer.class ); +Root personRoot = criteria.from( Person.class ); +criteria.select( personRoot.get( Person_.age ) ); +criteria.where( builder.equal( personRoot.get( Person_.eyeColor ), "brown" ) ); +List ages = em.createQuery( criteria ).getResultList(); +for ( Integer age : ages ) { ... } ]]> + + + + + Notice again the typing of the query based on the anticipated result type(s). Here + we are specifying java.lang.Integer as the type of the + Person#age attribute is java.lang.Integer. + + + + + We need to bind the fact that we are interested in the age associated with the + personRoot. We might have multiple references to the Person + entity in the query so we need to identify (aka qualify) which + Person#age we mean. + + + + + + Selecting an expression + + + + + criteria = builder.createQuery( Integer.class ); +Root personRoot = criteria.from( Person.class ); +criteria.select( builder.max( personRoot.get( Person_.age ) ) ); +criteria.where( builder.equal( personRoot.get( Person_.eyeColor ), "brown" ) ); +Integer maxAge = em.createQuery( criteria ).getSingleResult();]]> + + + + + Here we see javax.persistence.criteria.CriteriaBuilder + used to obtain a MAX expression. These expression building + methods return javax.persistence.criteria.Expression + instances typed according to various rules. The rule for a MAX + expression is that the expression type is the same as that of the underlying attribute. + + + +
-
- FROM clause -
- - - JPA 2 Specification - - - - A CriteriaQuery object defines a query over one or more entity, embeddable, or basic abstract - schema types. The root objects of the query are entities, from which the other types are reached - by navigation. - -
- All the individual parts of the FROM clause (roots, joins, paths) implement the - javax.persistence.criteria.From - interface. + +
+ Selecting multiple values + + There are actually a few different ways to select multiple values using criteria queries. We will + explore 2 options here, but an alternative recommended approach is to use tuples as + described in -
- Roots - Roots define the basis from which all joins, paths and attributes are available in the query. It - is - the root of the portion of your domain model you wish to query against. In a criteria query, a root - is always an entity. Roots are defined and added to the criteria by the overloaded - from - methods onjavax.persistence.criteria.CriteriaQuery: - - Root from(Class)]]> - Root from(EntityType)]]> + + Selecting an array + + + + + + + + + criteria = builder.createQuery( Object[].class ); +Root personRoot = criteria.from( Person.class ); +Path idPath = personRoot.get( Person_.id ); +Path agePath = personRoot.get( Person_.age ); +criteria.select( builder.array( idPath, agePath ) ); +criteria.where( builder.equal( personRoot.get( Person_.eyeColor ), "brown" ) ); +List valueArray = em.createQuery( criteria ).getResultList(); +for ( Object[] values : valueArray ) { + final Long id = (Long) values[0]; + final Integer age = (Integer) values[1]; + ... +}]]> + + + + + Technically this is classified as a typed query, but as you can see in handling the + results that is sort of misleading. Anyway, the expected result type here is an + array. + + + + + Here we see the use of the array method of the + javax.persistence.criteria.CriteriaBuilder which + explicitly combines individual selections into a + javax.persistence.criteria.CompoundSelection. + + + + + + Selecting an array (2) + + + + + + + + + criteria = builder.createQuery( Object[].class ); +Root personRoot = criteria.from( Person.class ); +Path idPath = personRoot.get( Person_.id ); +Path agePath = personRoot.get( Person_.age ); +criteria.multiselect( idPath, agePath ); +criteria.where( builder.equal( personRoot.get( Person_.eyeColor ), "brown" ) ); +List valueArray = em.createQuery( criteria ).getResultList(); +for ( Object[] values : valueArray ) { + final Long id = (Long) values[0]; + final Integer age = (Integer) values[1]; + ... +} ]]> + + + + + Just as we saw in we have + a "typed" criteria query returning an Object array. + + + + + This actually functions exactly the same as what we saw in + . The multiselect + method behaves slightly differently based on the type given when the criteria query + was first built, but in this case it says to select and return an + Object[]. + + + + +
+ +
+ Selecting a wrapper + + Another alternative to is to instead select + an object that will "wrap" the multiple values. Going back to the example query there, rather than + returning an array of [Person#id, Person#age] instead declare a class + that holds these values and instead return that. + + + Selecting an wrapper + + + + + + + + + + + + + + + + criteria = builder.createQuery( PersonWrapper.class ); +Root personRoot = criteria.from( Person.class ); +criteria.select( + builder.construct( + PersonWrapper.class, + personRoot.get( Person_.id ), + personRoot.get( Person_.age ) + ) +); +criteria.where( builder.equal( personRoot.get( Person_.eyeColor ), "brown" ) ); +List people = em.createQuery( criteria ).getResultList(); +for ( PersonWrapper person : people ) { ... }]]> + + + + + First we see the simple definition of the wrapper object we will be using to + wrap our result values. Specifically notice the constructor and its argument types. + + + + + Since we will be returning PersonWrapper objects, we + use PersonWrapper as the type of our criteria query. + + + + + Here we see another new javax.persistence.criteria.CriteriaBuilder + method, construct, which is used to builder a wrapper + expression. Basically for every row in the result we are saying we would like + a PersonWrapper instantiated by the matching constructor. This + wrapper expression is then passed as the select. + + + + +
+ +
+ +
+ Tuple criteria queries + + A better approach to is to either use + a wrapper (which we just saw in ) or using + the javax.persistence.Tuple contract. + + + + Selecting a tuple + + + + + + + + + + + + + criteria = builder.createTupleQuery(); +Root personRoot = criteria.from( Person.class ); +Path idPath = personRoot.get( Person_.id ); +Path agePath = personRoot.get( Person_.age ); +criteria.multiselect( idPath, agePath ); +criteria.where( builder.equal( personRoot.get( Person_.eyeColor ), "brown" ) ); +List tuples = em.createQuery( criteria ).getResultList(); +for ( Tuple tuple : valueArray ) { + assert tuple.get( 0 ) == tuple.get( idPath ); + assert tuple.get( 1 ) == tuple.get( agePath ); + ... +} ]]> + + + + + Here we see the use of a new javax.persistence.criteria.CriteriaBuilder + javax.persistence.criteria.CriteriaQuery building method, + createTupleQuery. This is exactly equivalent to calling + builder.createQuery( Tuple.class ). It signifies that we want + to access the results through the javax.persistence.Tuple contract. + + + + + Again we see the use of the multiselect method, just like + in . The difference here is that the + type of the javax.persistence.criteria.CriteriaQuery was defined + as javax.persistence.Tuple so the compound selections in + this case are interpreted to be the tuple elements. + + + + + Here we see javax.persistence.Tuple allowing different types of + access to the results, which we will expand on next. + + + + + +
+ Accessing tuple elements + + The javax.persistence.Tuple contract provides 3 basic forms of + access to the underlying elements: + + + + typed + + X get(TupleElement tupleElement)]]> + + This allows typed access to the underlying tuple elements. We see this in + in the tuple.get( idPath ) + and tuple.get( agePath ) calls. Just about everything is a + javax.persistence.TupleElement. + + + + + positional + + + X get(int i, Class type)]]> + + Very similar to what we saw in and + in terms of positional access. Only the + second form here provides typing, because the user explicitly provides the typing + on access. We see this in in + the tuple.get( 0 ) and tuple.get( 1 ) calls. + + + + + aliased + + + X get(String alias, Class type)]]> + + Again, only the second form here provides typing, because the user explicitly provides + the typing on access. We have not seen an example of using this, but its trivial. We + would simply, for example, have applies an alias to either of the paths like + idPath.alias( "id" ) and/or agePath.alias( "age" ) + and we could have accessed the individual tuple elements by those specified aliases. + + + + +
+ +
+ + + +
+ FROM clause +
+ + + + + A CriteriaQuery object defines a query over one or more entity, embeddable, or basic abstract + schema types. The root objects of the query are entities, from which the other types are reached + by navigation. + +
+ + + + All the individual parts of the FROM clause (roots, joins, paths) implement the + javax.persistence.criteria.From interface. + + + +
+ Roots + + Roots define the basis from which all joins, paths and attributes are available in the query. In + a criteria query, a root is always an entity. Roots are defined and added to the criteria by + the overloaded from methods on + javax.persistence.criteria.CriteriaQuery: + + Root from(Class)]]> + Root from(EntityType)]]> + + Adding a root personCriteria = builder.createQuery( Person.class ); // create and add the root person.from( Person.class ); ...]]> - Criteria queries may define multiple roots, the effect of which is to create a cartesean product - between the newly added root and the others. Here is an example matching all single men and all - single women: - - + + + Criteria queries may define multiple roots, the effect of which is to create a + cartesian product + between the newly added root and the others. Here is an example matching all single men and all + single women: + + men = query.from( Person.class ); Root women = query.from( Person.class ); Predicate menRestriction = builder.and( - builder.equal( - men.get( Person_.gender ), - Gender.MALE - ), - builder.equal( - men.get( Person_.relationshipStatus ), - RelationshipStatus.SINGLE - ) + builder.equal( men.get( Person_.gender ), Gender.MALE ), + builder.equal( men.get( Person_.relationshipStatus ), RelationshipStatus.SINGLE ) ); Predicate womenRestriction = builder.and( - builder.equal( - women.get( Person_.gender ), - Gender.FEMALE - ), - builder.equal( - women.get( Person_.relationshipStatus ), - RelationshipStatus.SINGLE - ) + builder.equal( women.get( Person_.gender ), Gender.FEMALE ), + builder.equal( women.get( Person_.relationshipStatus ), RelationshipStatus.SINGLE ) ); -query.where( - builder.and( menRestriction, womenRestriction ) -);]]> -
-
- Joins - Joins allow navigation from other - javax.persistence.criteria.From - to either association or embedded attributes. Joins are created by the numerous overloaded - join - methods of the - javax.persistence.criteria.From - interface: - +query.where( builder.and( menRestriction, womenRestriction ) );]]> +
+ +
+ Joins + Joins allow navigation from other + javax.persistence.criteria.From + to either association or embedded attributes. Joins are created by the numerous overloaded + join + methods of the + javax.persistence.criteria.From + interface: + + + Example with Embedded and ManyToOne personCriteria = builder.createQuery( Person.class ); Root personRoot = person.from( Person.class ); // Person.address is an embedded attribute @@ -245,128 +559,105 @@ Join personAddress = personRoot.join( Person_.address ); // Address.country is a ManyToOne Join addressCountry = personAddress.join( Address_.country ); ...]]> - An example with collection attributes: + + + Example with Collections personCriteria = builder.createQuery( Person.class ); Root personRoot = person.from( Person.class ); Join orders = personRoot.join( Person_.orders ); Join orderLines = orders.join( Order_.lineItems ); ...]]> -
-
- Fetches - todo -
+
+ +
+ Fetches + + Just like in HQL and EJB-QL, we can specify that associated data be fetched along with the owner. + Fetches are created by the numerous overloaded fetch + methods of the javax.persistence.criteria.From + interface: + + + Example with Embedded and ManyToOne + personCriteria = builder.createQuery( Person.class ); +Root personRoot = person.from( Person.class ); +// Person.address is an embedded attribute +Join personAddress = personRoot.fetch( Person_.address ); +// Address.country is a ManyToOne +Join addressCountry = personAddress.fetch( Address_.country ); +...]]> + + + + Technically speaking, embedded attributes are always fetched with their owner. However + in order to define the fetching of Address#country we needed + a javax.persistence.criteria.Fetch for its parent path. + + + + Example with Collections + personCriteria = builder.createQuery( Person.class ); +Root personRoot = person.from( Person.class ); +Join orders = personRoot.fetch( Person_.orders ); +Join orderLines = orders.fetch( Order_.lineItems ); +...]]> + +
+ +
+
Path expressions - Roots, joins and fetches are themselves paths as well + Roots, joins and fetches are themselves paths as well. - todo
-
- Selections - todo -
-
-
- Criteria query execution - todo -
-
- Common use cases -
- Selecting the root entity - personCriteria = build.createQuery( Person.class ); -Root personRoot = personCriteria.from( Person.class ); -// specifying select here is not strictly needed because 'personRoot' -// will be the implied selection since we have only a single root; -// but done here for explicitness -personCriteria.select( personRoot ); -personCriteria.where( builder.equal( Person_.eyeColor, "brown" ) ); -List people = em.createQuery( personCriteria ).getResultList();]]> -
-
- Selecting an association - personCriteria = build.createQuery( Gender.class ); -Root personRoot = personCriteria.from( Person.class ); -// specifying select here is not strictly needed because 'personRoot' -// will be the implied selection since we have only a single root; -// but done here for explicitness -personCriteria.select( personRoot ); -personCriteria.where( builder.equal( Person_.eyeColor, "brown" ) ); -List people = em.createQuery( personCriteria ).getResultList();]]> -
-
- Selecting a value - personCriteria = build.createQuery( Integer.class ); -Root personRoot = personCriteria.from( Person.class ); -personCriteria.select( personRoot.get( Person.height ) ); -personCriteria.where( builder.equal( Person_.eyeColor, "brown" ) ); -List heights = em.createQuery( personCriteria ).getResultList();]]> -
-
- Selecting an aggregated value - personCriteria = build.createQuery( Integer.class ); -Root personRoot = personCriteria.from( Person.class ); -personCriteria.select( builder.max( personRoot.get( Person.height ) ) ); -personCriteria.where( builder.equal( Person_.eyeColor, "brown" ) ); -Integer maxHeight = em.createQuery( personCriteria ).getSingleResult();]]> -
-
- Selecting a tuple - personCriteria = build.createTupleQuery(); -Root personRoot = personCriteria.from( Person.class ); -Path idPath = personRoot.get( Person_.id ); -idPath.setAlias( "id" ); -Path heightPath = personRoot.get( Person_.height ); -Path genderPath = personRoot.get( Person_.gender ); -personCriteria.multiselect( idPath, heightPath, genderPath ); -personCriteria.where( builder.equal( Person_.eyeColor, "brown" ) ); -List tuples = em.createQuery( personCriteria ).getResultList(); -for ( Tuple tuple : tuples ) { - // the id value, for example, can be accessed by expression... - handleId( tuple.get( idPath ) ); - // or by position... - handleId( tuple.get( 0 ) ); - // or by the explicit alias we gave it... - handleId( tuple.get( "id" ) ); -}]]> -
-
- Selecting a constructed value - personCriteria = build.createQuery( PersonHolder.class ); -Root personRoot = personCriteria.from( Person.class ); -personCriteria.select( - builder.construct( - PersonHolder.class, - personRoot.get( Person_.id ), - personRoot.get( Person_.height ), - personRoot.get( Person_.gender ) - ) -); -List people = em.createQuery( personCriteria ).getResultList();]]> -
-
+ + +
+ Using parameters + Using parameters - personCriteria = build.createQuery( Person.class ); -Root personRoot = personCriteria.from( Person.class ); -personCriteria.select( personRoot ); + + + + + + + criteria = build.createQuery( Person.class ); +Root personRoot = criteria.from( Person.class ); +criteria.select( personRoot ); ParameterExpression eyeColorParam = builder.parameter( String.class ); -personCriteria.where( builder.equal( Person_.eyeColor, eyeColorParam ) ); -TypedQuery query = em.createQuery( personCriteria ); +criteria.where( builder.equal( personRoot.get( Person_.eyeColor ), eyeColorParam ) ); +TypedQuery query = em.createQuery( criteria ); query.setParameter( eyeColorParam, "brown" ); List people = query.getResultList();]]> -
+ + + + Use the parameter method of + javax.persistence.criteria.CriteriaBuilder + to obtain a parameter reference. + + + + + Use the parameter reference in the criteria query. + + + + + Use the parameter reference to bind the parameter value to the + javax.persistence.TypedQuery + + + + + +
+