diff --git a/documentation/src/main/docbook/userGuide/en-US/Hibernate_User_Guide.xml b/documentation/src/main/docbook/userGuide/en-US/Hibernate_User_Guide.xml index 9fd4841518..3774f55dce 100644 --- a/documentation/src/main/docbook/userGuide/en-US/Hibernate_User_Guide.xml +++ b/documentation/src/main/docbook/userGuide/en-US/Hibernate_User_Guide.xml @@ -58,15 +58,18 @@ + + + - + + + diff --git a/documentation/src/main/docbook/userGuide/en-US/appendices/Appendix_LegacyBootstrap.xml b/documentation/src/main/docbook/userGuide/en-US/appendices/Legacy_Bootstrap.xml similarity index 100% rename from documentation/src/main/docbook/userGuide/en-US/appendices/Appendix_LegacyBootstrap.xml rename to documentation/src/main/docbook/userGuide/en-US/appendices/Legacy_Bootstrap.xml diff --git a/documentation/src/main/docbook/userGuide/en-US/appendices/Legacy_Criteria.xml b/documentation/src/main/docbook/userGuide/en-US/appendices/Legacy_Criteria.xml new file mode 100644 index 0000000000..a4e472401d --- /dev/null +++ b/documentation/src/main/docbook/userGuide/en-US/appendices/Legacy_Criteria.xml @@ -0,0 +1,549 @@ + + + + + + Legacy Hibernate Criteria Queries + + + + + This appendix covers the legacy Hibernate org.hibernate.Criteria API, which + should be considered deprecated. New development should focus on the JPA + javax.persistence.criteria.CriteriaQuery API. Eventually, + Hibernate-specific criteria features will be ported as extensions to the JPA + javax.persistence.criteria.CriteriaQuery. For details on the JPA APIs, see + . + + + This information is copied as-is from the older Hibernate documentation. + + + + + Hibernate features an intuitive, extensible criteria query API. + + +
+ Creating a <literal>Criteria</literal> instance + + + The interface org.hibernate.Criteria represents a query against + a particular persistent class. The Session is a factory for + Criteria instances. + + + + +
+ +
+ Narrowing the result set + + + An individual query criterion is an instance of the interface + org.hibernate.criterion.Criterion. The class + org.hibernate.criterion.Restrictions defines + factory methods for obtaining certain built-in + Criterion types. + + + + + + Restrictions can be grouped logically. + + + + + + + + There are a range of built-in criterion types (Restrictions + subclasses). One of the most useful allows you to specify SQL directly. + + + + + + The {alias} placeholder will be replaced by the row alias + of the queried entity. + + + + You can also obtain a criterion from a + Property instance. You can create a Property + by calling Property.forName(): + + + + +
+ +
+ Ordering the results + + + You can order the results using org.hibernate.criterion.Order. + + + + + + +
+ +
+ Associations + + + By navigating + associations using createCriteria() you can specify constraints upon related entities: + + + + + + The second createCriteria() returns a new + instance of Criteria that refers to the elements of + the kittens collection. + + + + There is also an alternate form that is useful in certain circumstances: + + + + + + (createAlias() does not create a new instance of + Criteria.) + + + + The kittens collections held by the Cat instances + returned by the previous two queries are not pre-filtered + by the criteria. If you want to retrieve just the kittens that match the + criteria, you must use a ResultTransformer. + + + + + + Additionally you may manipulate the result set using a left outer join: + + + + + This will return all of the Cats with a mate whose name starts with "good" + ordered by their mate's age, and all cats who do not have a mate. + This is useful when there is a need to order or limit in the database + prior to returning complex/large result sets, and removes many instances where + multiple queries would have to be performed and the results unioned + by java in memory. + + + Without this feature, first all of the cats without a mate would need to be loaded in one query. + + + A second query would need to retreive the cats with mates who's name started with "good" sorted by the mates age. + + + Thirdly, in memory; the lists would need to be joined manually. + +
+ +
+ Dynamic association fetching + + + You can specify association fetching semantics at runtime using + setFetchMode(). + + + + + + This query will fetch both mate and kittens + by outer join. + + +
+ +
+ Components + + + To add a restriction against a property of an embedded component, the component property + name should be prepended to the property name when creating the Restriction. + The criteria object should be created on the owning entity, and cannot be created on the component + itself. For example, suppose the Cat has a component property fullName + with sub-properties firstName and lastName: + + + + + + + Note: this does not apply when querying collections of components, for that see below + + + +
+ +
+ Collections + + When using criteria against collections, there are two distinct cases. One is if + the collection contains entities (eg. <one-to-many/> + or <many-to-many/>) or components + (<composite-element/> ), + and the second is if the collection contains scalar values + (<element/>). + In the first case, the syntax is as given above in the section + where we restrict the kittens + collection. Essentially we create a Criteria object against the collection + property and restrict the entity or component properties using that instance. + + + For queryng a collection of basic values, we still create the Criteria + object against the collection, but to reference the value, we use the special property + "elements". For an indexed collection, we can also reference the index property using + the special property "indices". + + + +
+ +
+ Example queries + + + The class org.hibernate.criterion.Example allows + you to construct a query criterion from a given instance. + + + + + + Version properties, identifiers and associations are ignored. By default, + null valued properties are excluded. + + + + You can adjust how the Example is applied. + + + + + + You can even use examples to place criteria upon associated objects. + + + + +
+ +
+ Projections, aggregation and grouping + + The class org.hibernate.criterion.Projections is a + factory for Projection instances. You can apply a + projection to a query by calling setProjection(). + + + + + + + + There is no explicit "group by" necessary in a criteria query. Certain + projection types are defined to be grouping projections, + which also appear in the SQL group by clause. + + + + An alias can be assigned to a projection so that the projected value + can be referred to in restrictions or orderings. Here are two different ways to + do this: + + + + + + + + The alias() and as() methods simply wrap a + projection instance in another, aliased, instance of Projection. + As a shortcut, you can assign an alias when you add the projection to a + projection list: + + + + + + + + You can also use Property.forName() to express projections: + + + + + + +
+ +
+ Detached queries and subqueries + + The DetachedCriteria class allows you to create a query outside the scope + of a session and then execute it using an arbitrary Session. + + + + + + A DetachedCriteria can also be used to express a subquery. Criterion + instances involving subqueries can be obtained via Subqueries or + Property. + + + + + + + + Correlated subqueries are also possible: + + + + + + Example of multi-column restriction based on a subquery: + + + + +
+ + + +
+ Queries by natural identifier + + + For most queries, including criteria queries, the query cache is not efficient + because query cache invalidation occurs too frequently. However, there is a special + kind of query where you can optimize the cache invalidation algorithm: lookups by a + constant natural key. In some applications, this kind of query occurs frequently. + The criteria API provides special provision for this use case. + + + + First, map the natural key of your entity using + <natural-id> and enable use of the second-level cache. + + + + + + + + + + + + +]]> + + + This functionality is not intended for use with entities with + mutable natural keys. + + + + Once you have enabled the Hibernate query cache, + the Restrictions.naturalId() allows you to make use of + the more efficient cache algorithm. + + + + +
+ +
diff --git a/documentation/src/main/docbook/userGuide/en-US/chapters/fetching/Fetching.xml b/documentation/src/main/docbook/userGuide/en-US/chapters/fetching/Fetching.xml index 868312037a..c32a2157ce 100644 --- a/documentation/src/main/docbook/userGuide/en-US/chapters/fetching/Fetching.xml +++ b/documentation/src/main/docbook/userGuide/en-US/chapters/fetching/Fetching.xml @@ -11,6 +11,10 @@ xmlns:xi="http://www.w3.org/2001/XInclude"> Fetching + + + + Fetching, essentially, is the process of grabbing data from the database and making it available to the application. Tuning how an application does fetching is one of the biggest factors in determining how an @@ -76,6 +80,11 @@ + + + Starting in Hibernate 4.2 (JPA 2.1) you can also use JPA EntityGraphs. + + @@ -143,7 +152,7 @@ The Hibernate recommendation is to statically mark all associations lazy and to use dynamic fetching strategies for eagerness. This is unfortunately at odds with the JPA specification which defines that all one-to-one and many-to-one associations should be eagerly fetched by default. Hibernate, as a JPA - provider honors that default. + provider, honors that default. @@ -195,8 +204,8 @@ In this example we have an Employee and their Projects loaded in a single query shown both as an HQL - query and a JPA Criteria query. In both cases, this resolves to exactly one database query to get - all that information. + query and a JPA Criteria query. In both cases, this resolves to exactly one database query to get all + that information. @@ -226,7 +235,4 @@ - - - \ No newline at end of file diff --git a/documentation/src/main/docbook/userGuide/en-US/chapters/query-criteria/Criteria.xml b/documentation/src/main/docbook/userGuide/en-US/chapters/query-criteria/Criteria.xml new file mode 100644 index 0000000000..184c73d2be --- /dev/null +++ b/documentation/src/main/docbook/userGuide/en-US/chapters/query-criteria/Criteria.xml @@ -0,0 +1,413 @@ + + + + + + Criteria + + + Criteria queries offer a type-safe alternative to HQL, JPQL and native-sql queries. + + + + + Hibernate offers an older, legacy org.hibernate.Criteria API which should be + considered deprecated. No feature development will target those APIs. Eventually, Hibernate-specific + criteria features will be ported as extensions to the JPA + javax.persistence.criteria.CriteriaQuery. For details on the + org.hibernate.Criteria API, see . + + + This chapter will focus on the JPA APIs for declaring type-safe criteria queries. + + + + + + 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 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. + + + + 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 either + javax.persistence.EntityManagerFactory or + javax.persistence.EntityManager. + + + + The next step is to obtain a javax.persistence.criteria.CriteriaQuery. This + is accomplished using one of the 3 methods on + javax.persistence.criteria.CriteriaBuilder for this purpose: + + + + + + Each serves a different purpose depending on the expected type of the query results. + + + + + Chapter 6 Criteria API of the JPA Specification + 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. + + + +
+ Typed criteria queries + + + The type of the criteria query (aka the ]]>) indicates the expected types in the query + result. This might be an entity, an Integer, or any other object. + + +
+ Selecting an entity + + + This is probably the most common form of query. The application wants to select entity instances. + + + + Selecting the root entity + + + + + The example uses createQuery passing in the Person + class reference as the results of the query will be Person objects. + + + + + The call to the CriteriaQuery.select method in this example is + unnecessary because personRoot will be the implied selection since we + have only a single query root. It was done here only for completeness of an example. + + + The Person_.eyeColor reference is an example of the static form of JPA + metamodel reference. We will use that form exclusively in this chapter. See + the documentation for the Hibernate JPA Metamodel Generator for additional details on + the JPA static metamodel. + + +
+ +
+ Selecting an expression + + + The simplest form of selecting an expression is selecting a particular attribute from an entity. + But this expression might also represent an aggregation, a mathematical operation, etc. + + + + Selecting an attribute + + + + + In this example, the query is typed as java.lang.Integer because that + is the anticipated type of the results (the type of the Person#age attribute + is java.lang.Integer). Because a query might contain multiple references to + the Person entity, attribute references always need to be qualified. This is accomplished by the + Root#get method call. + +
+ + +
+ 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 + . Or consider a wrapper query; see + for details. + + + + Selecting an array + + + + + Technically this is classified as a typed query, but you can see from handling the results that + this is sort of misleading. Anyway, the expected result type here is an array. + + + + The example then uses the array method of + javax.persistence.criteria.CriteriaBuilder which explicitly + combines individual selections into a + javax.persistence.criteria.CompoundSelection. + + + + Selecting an array (2) + + + + + Just as we saw in we have a typed criteria + query returning an Object array. Both queries are functionally equivalent. This second example + uses the multiselect method which 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 + + + + + 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. + + + + This example illustrates the use of the + javax.persistence.criteria.CriteriaBuilder method + construct which is used to build a wrapper expression. For every row in the + result we are saying we would like a PersonWrapper instantiated with + the remaining arguments by the matching constructor. This wrapper expression is then passed as + the select. + +
+
+ +
+ Tuple criteria queries + + + A better approach to is to use either a + wrapper (which we just saw in ) or using the + javax.persistence.Tuple contract. + + + + Selecting a tuple + + + + + This example illustrates accessing the query results through the + javax.persistence.Tuple interface. The example uses the explicit + createTupleQuery of + javax.persistence.criteria.CriteriaBuilder. An alternate approach + is to use createQuery passing Tuple.class. + + + + 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. + + + + The javax.persistence.Tuple contract provides 3 forms of access to + the underlying elements: + + + + + typed + + + The example illustrates this form of access + in the tuple.get( idPath ) and tuple.get( agePath ) calls. + This allows typed access to the underlying tuple values based on the + javax.persistence.TupleElement expressions used to build + the criteria. + + + + + positional + + + Allows access to the underlying tuple values based on the position. The simple + Object get(int position) form is very similar to the access + illustrated in and + . The + X get(int position, Class type]]> form + allows typed positional access, but based on the explicitly supplied type which the tuple + value must be type-assignable to. + + + + + aliased + + + Allows access to the underlying tuple values based an (optionally) assigned alias. The + example query did not apply an alias. An alias would be applied via the + alias method on + javax.persistence.criteria.Selection. Just like + positional access, there is both a typed + (Object get(String alias)) and an untyped + ( X get(String alias, Class type]]> form. + + + + +
+ +
+ FROM clause + +
+ JPA Specification, section 6.5.2 Query Roots, pg 262 + + + 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. + A root is always an entity type. Roots are defined and added to the criteria by the overloaded + from methods on + javax.persistence.criteria.CriteriaQuery: + + + + + + Adding a root + + + + + 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: + + + + Adding multiple roots + + +
+ +
+ 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 + + + + + Example with Collections + + +
+ +
+ Fetches + + + Just like in HQL and JPQL, criteria queries 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 + + + + + + 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 + + +
+
+ +
+ Path expressions + + + Roots, joins and fetches are themselves paths as well. + + +
+ +
+ Using parameters + + + Using parameters + + + + + Use the parameter method of + javax.persistence.criteria.CriteriaBuilder to obtain a parameter + reference. Then use the parameter reference to bind the parameter value to the + javax.persistence.Query + +
+ +
diff --git a/documentation/src/main/docbook/userGuide/en-US/chapters/query-criteria/extras/CriteriaBuilder_query_creation_snippet.java b/documentation/src/main/docbook/userGuide/en-US/chapters/query-criteria/extras/CriteriaBuilder_query_creation_snippet.java new file mode 100644 index 0000000000..a4dc3ef01b --- /dev/null +++ b/documentation/src/main/docbook/userGuide/en-US/chapters/query-criteria/extras/CriteriaBuilder_query_creation_snippet.java @@ -0,0 +1,3 @@ + CriteriaQuery createQuery(Class resultClass); +CriteriaQuery createTupleQuery(); +CriteriaQuery createQuery(); diff --git a/documentation/src/main/docbook/userGuide/en-US/chapters/query-criteria/extras/from_fetch_example_embedded_and_many2one.java b/documentation/src/main/docbook/userGuide/en-US/chapters/query-criteria/extras/from_fetch_example_embedded_and_many2one.java new file mode 100644 index 0000000000..fe68976760 --- /dev/null +++ b/documentation/src/main/docbook/userGuide/en-US/chapters/query-criteria/extras/from_fetch_example_embedded_and_many2one.java @@ -0,0 +1,6 @@ +CriteriaQuery personCriteria = builder.createQuery( Person.class ); +Root personRoot = person.from( Person.class ); +// Person.address is an embedded attribute +Fetch personAddress = personRoot.fetch( Person_.address ); +// Address.country is a ManyToOne +Fetch addressCountry = personAddress.fetch( Address_.country ); \ No newline at end of file diff --git a/documentation/src/main/docbook/userGuide/en-US/chapters/query-criteria/extras/from_fetch_example_plural.java b/documentation/src/main/docbook/userGuide/en-US/chapters/query-criteria/extras/from_fetch_example_plural.java new file mode 100644 index 0000000000..5a216e28ef --- /dev/null +++ b/documentation/src/main/docbook/userGuide/en-US/chapters/query-criteria/extras/from_fetch_example_plural.java @@ -0,0 +1,4 @@ +CriteriaQuery<Person> personCriteria = builder.createQuery( Person.class ); +Root personRoot = person.from( Person.class ); +Fetch orders = personRoot.fetch( Person_.orders ); +Fetch orderLines = orders.fetch( Order_.lineItems ); \ No newline at end of file diff --git a/documentation/src/main/docbook/userGuide/en-US/chapters/query-criteria/extras/from_join_example_embedded_and_many2one.java b/documentation/src/main/docbook/userGuide/en-US/chapters/query-criteria/extras/from_join_example_embedded_and_many2one.java new file mode 100644 index 0000000000..478b649cac --- /dev/null +++ b/documentation/src/main/docbook/userGuide/en-US/chapters/query-criteria/extras/from_join_example_embedded_and_many2one.java @@ -0,0 +1,6 @@ +CriteriaQuery personCriteria = builder.createQuery( Person.class ); +Root personRoot = person.from( Person.class ); +// Person.address is an embedded attribute +Join personAddress = personRoot.join( Person_.address ); +// Address.country is a ManyToOne +Join addressCountry = personAddress.join( Address_.country ); \ No newline at end of file diff --git a/documentation/src/main/docbook/userGuide/en-US/chapters/query-criteria/extras/from_join_example_plural.java b/documentation/src/main/docbook/userGuide/en-US/chapters/query-criteria/extras/from_join_example_plural.java new file mode 100644 index 0000000000..1840bad318 --- /dev/null +++ b/documentation/src/main/docbook/userGuide/en-US/chapters/query-criteria/extras/from_join_example_plural.java @@ -0,0 +1,4 @@ +CriteriaQuery personCriteria = builder.createQuery( Person.class ); +Root personRoot = person.from( Person.class ); +Join orders = personRoot.join( Person_.orders ); +Join orderLines = orders.join( Order_.lineItems ); \ No newline at end of file diff --git a/documentation/src/main/docbook/userGuide/en-US/chapters/query-criteria/extras/from_root_example.java b/documentation/src/main/docbook/userGuide/en-US/chapters/query-criteria/extras/from_root_example.java new file mode 100644 index 0000000000..0c73ad04ff --- /dev/null +++ b/documentation/src/main/docbook/userGuide/en-US/chapters/query-criteria/extras/from_root_example.java @@ -0,0 +1,3 @@ +CriteriaQuery personCriteria = builder.createQuery( Person.class ); +// create and add the root +person.from( Person.class ); \ No newline at end of file diff --git a/documentation/src/main/docbook/userGuide/en-US/chapters/query-criteria/extras/from_root_example_multiple.java b/documentation/src/main/docbook/userGuide/en-US/chapters/query-criteria/extras/from_root_example_multiple.java new file mode 100644 index 0000000000..e37cbc17a4 --- /dev/null +++ b/documentation/src/main/docbook/userGuide/en-US/chapters/query-criteria/extras/from_root_example_multiple.java @@ -0,0 +1,12 @@ +CriteriaQuery query = builder.createQuery(); +Root 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 ) +); +Predicate womenRestriction = builder.and( + builder.equal( women.get( Person_.gender ), Gender.FEMALE ), + builder.equal( women.get( Person_.relationshipStatus ), RelationshipStatus.SINGLE ) +); +query.where( builder.and( menRestriction, womenRestriction ) ); \ No newline at end of file diff --git a/documentation/src/main/docbook/userGuide/en-US/chapters/query-criteria/extras/from_root_methods.java b/documentation/src/main/docbook/userGuide/en-US/chapters/query-criteria/extras/from_root_methods.java new file mode 100644 index 0000000000..4a9c915904 --- /dev/null +++ b/documentation/src/main/docbook/userGuide/en-US/chapters/query-criteria/extras/from_root_methods.java @@ -0,0 +1,3 @@ + Root from(Class); + + Root from(EntityType) \ No newline at end of file diff --git a/documentation/src/main/docbook/userGuide/en-US/chapters/query-criteria/extras/parameter_example.java b/documentation/src/main/docbook/userGuide/en-US/chapters/query-criteria/extras/parameter_example.java new file mode 100644 index 0000000000..bcb72ff2b4 --- /dev/null +++ b/documentation/src/main/docbook/userGuide/en-US/chapters/query-criteria/extras/parameter_example.java @@ -0,0 +1,9 @@ +CriteriaQuery criteria = build.createQuery( Person.class ); +Root personRoot = criteria.from( Person.class ); +criteria.select( personRoot ); +ParameterExpression eyeColorParam = builder.parameter( String.class ); +criteria.where( builder.equal( personRoot.get( Person_.eyeColor ), eyeColorParam ) ); + +TypedQuery query = em.createQuery( criteria ); +query.setParameter( eyeColorParam, "brown" ); +List people = query.getResultList(); \ No newline at end of file diff --git a/documentation/src/main/docbook/userGuide/en-US/chapters/query-criteria/extras/select_attribute_example.java b/documentation/src/main/docbook/userGuide/en-US/chapters/query-criteria/extras/select_attribute_example.java new file mode 100644 index 0000000000..0667a435e9 --- /dev/null +++ b/documentation/src/main/docbook/userGuide/en-US/chapters/query-criteria/extras/select_attribute_example.java @@ -0,0 +1,9 @@ +CriteriaQuery 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 ) { + ... +} \ No newline at end of file diff --git a/documentation/src/main/docbook/userGuide/en-US/chapters/query-criteria/extras/select_multiple_values_array.java b/documentation/src/main/docbook/userGuide/en-US/chapters/query-criteria/extras/select_multiple_values_array.java new file mode 100644 index 0000000000..7e3fefaa18 --- /dev/null +++ b/documentation/src/main/docbook/userGuide/en-US/chapters/query-criteria/extras/select_multiple_values_array.java @@ -0,0 +1,13 @@ +CriteriaQuery 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]; + ... +} \ No newline at end of file diff --git a/documentation/src/main/docbook/userGuide/en-US/chapters/query-criteria/extras/select_multiple_values_array2.java b/documentation/src/main/docbook/userGuide/en-US/chapters/query-criteria/extras/select_multiple_values_array2.java new file mode 100644 index 0000000000..75c8feeaa3 --- /dev/null +++ b/documentation/src/main/docbook/userGuide/en-US/chapters/query-criteria/extras/select_multiple_values_array2.java @@ -0,0 +1,13 @@ +CriteriaQuery 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]; + ... +} \ No newline at end of file diff --git a/documentation/src/main/docbook/userGuide/en-US/chapters/query-criteria/extras/select_root_entity_example.java b/documentation/src/main/docbook/userGuide/en-US/chapters/query-criteria/extras/select_root_entity_example.java new file mode 100644 index 0000000000..c60921d116 --- /dev/null +++ b/documentation/src/main/docbook/userGuide/en-US/chapters/query-criteria/extras/select_root_entity_example.java @@ -0,0 +1,9 @@ +CriteriaQuery 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 ) { + ... +} \ No newline at end of file diff --git a/documentation/src/main/docbook/userGuide/en-US/chapters/query-criteria/extras/select_tuple.java b/documentation/src/main/docbook/userGuide/en-US/chapters/query-criteria/extras/select_tuple.java new file mode 100644 index 0000000000..dc651c1cf0 --- /dev/null +++ b/documentation/src/main/docbook/userGuide/en-US/chapters/query-criteria/extras/select_tuple.java @@ -0,0 +1,13 @@ +CriteriaQuery 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 ); + ... +} \ No newline at end of file diff --git a/documentation/src/main/docbook/userGuide/en-US/chapters/query-criteria/extras/select_wrapper.java b/documentation/src/main/docbook/userGuide/en-US/chapters/query-criteria/extras/select_wrapper.java new file mode 100644 index 0000000000..f82398829f --- /dev/null +++ b/documentation/src/main/docbook/userGuide/en-US/chapters/query-criteria/extras/select_wrapper.java @@ -0,0 +1,27 @@ +public class PersonWrapper { + private final Long id; + private final Integer age; + public PersonWrapper(Long id, Integer age) { + this.id = id; + this.age = age; + } + ... +} + +... + +CriteriaQuery 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 ) { + ... +} \ No newline at end of file diff --git a/documentation/src/main/docbook/userGuide/en-US/chapters/query-native/Native.xml b/documentation/src/main/docbook/userGuide/en-US/chapters/query-native/Native.xml new file mode 100644 index 0000000000..a5f0e8f107 --- /dev/null +++ b/documentation/src/main/docbook/userGuide/en-US/chapters/query-native/Native.xml @@ -0,0 +1,1126 @@ + + + + + + Native SQL Queries + + + You may also express queries in the native SQL dialect of your database. This is useful if you + want to utilize database specific features such as query hints or the CONNECT BY option in Oracle. + It also provides a clean migration path from a direct SQL/JDBC based application to Hibernate/JPA. + Hibernate also allows you to specify handwritten SQL (including stored procedures) for all + create, update, delete, and load operations. + + +
+ Using a <literal>SQLQuery</literal> + + Execution of native SQL queries is controlled via the + SQLQuery interface, which is obtained by calling + Session.createSQLQuery(). The following sections + describe how to use this API for querying. + +
+ Scalar queries + + The most basic SQL query is to get a list of scalars + (values). + + sess.createSQLQuery("SELECT * FROM CATS").list(); +sess.createSQLQuery("SELECT ID, NAME, BIRTHDATE FROM CATS").list(); + + + These will return a List of Object arrays (Object[]) with scalar + values for each column in the CATS table. Hibernate will use + ResultSetMetadata to deduce the actual order and types of the returned + scalar values. + + To avoid the overhead of using + ResultSetMetadata, or simply to be more explicit in + what is returned, one can use addScalar(): + + sess.createSQLQuery("SELECT * FROM CATS") + .addScalar("ID", Hibernate.LONG) + .addScalar("NAME", Hibernate.STRING) + .addScalar("BIRTHDATE", Hibernate.DATE) + + + This query specified: + + + + the SQL query string + + + + the columns and types to return + + + + This will return Object arrays, but now it will not use + ResultSetMetadata but will instead explicitly get the + ID, NAME and BIRTHDATE column as respectively a Long, String and a Short + from the underlying resultset. This also means that only these three + columns will be returned, even though the query is using + * and could return more than the three listed + columns. + + It is possible to leave out the type information for all or some + of the scalars. + + sess.createSQLQuery("SELECT * FROM CATS") + .addScalar("ID", Hibernate.LONG) + .addScalar("NAME") + .addScalar("BIRTHDATE") + + + This is essentially the same query as before, but now + ResultSetMetaData is used to determine the type of + NAME and BIRTHDATE, where as the type of ID is explicitly + specified. + + How the java.sql.Types returned from ResultSetMetaData is mapped + to Hibernate types is controlled by the Dialect. If a specific type is + not mapped, or does not result in the expected type, it is possible to + customize it via calls to registerHibernateType in + the Dialect. +
+ +
+ Entity queries + + The above queries were all about returning scalar values, + basically returning the "raw" values from the resultset. The following + shows how to get entity objects from a native sql query via + addEntity(). + + sess.createSQLQuery("SELECT * FROM CATS").addEntity(Cat.class); +sess.createSQLQuery("SELECT ID, NAME, BIRTHDATE FROM CATS").addEntity(Cat.class); + + + This query specified: + + + + the SQL query string + + + + the entity returned by the query + + + + Assuming that Cat is mapped as a class with the columns ID, NAME + and BIRTHDATE the above queries will both return a List where each + element is a Cat entity. + + If the entity is mapped with a many-to-one to + another entity it is required to also return this when performing the + native query, otherwise a database specific "column not found" error + will occur. The additional columns will automatically be returned when + using the * notation, but we prefer to be explicit as in the following + example for a many-to-one to a + Dog: + + sess.createSQLQuery("SELECT ID, NAME, BIRTHDATE, DOG_ID FROM CATS").addEntity(Cat.class); + + + This will allow cat.getDog() to function properly. +
+ +
+ Handling associations and collections + + It is possible to eagerly join in the Dog to + avoid the possible extra roundtrip for initializing the proxy. This is + done via the addJoin() method, which allows you to + join in an association or collection. + + sess.createSQLQuery("SELECT c.ID, NAME, BIRTHDATE, DOG_ID, D_ID, D_NAME FROM CATS c, DOGS d WHERE c.DOG_ID = d.D_ID") + .addEntity("cat", Cat.class) + .addJoin("cat.dog"); + + + In this example, the returned Cat's will have + their dog property fully initialized without any + extra roundtrip to the database. Notice that you added an alias name + ("cat") to be able to specify the target property path of the join. It + is possible to do the same eager joining for collections, e.g. if the + Cat had a one-to-many to Dog + instead. + + sess.createSQLQuery("SELECT ID, NAME, BIRTHDATE, D_ID, D_NAME, CAT_ID FROM CATS c, DOGS d WHERE c.ID = d.CAT_ID") + .addEntity("cat", Cat.class) + .addJoin("cat.dogs"); + + + At this stage you are reaching the limits of what is possible with + native queries, without starting to enhance the sql queries to make them + usable in Hibernate. Problems can arise when returning multiple entities + of the same type or when the default alias/column names are not + enough. +
+ +
+ Returning multiple entities + + Until now, the result set column names are assumed to be the same + as the column names specified in the mapping document. This can be + problematic for SQL queries that join multiple tables, since the same + column names can appear in more than one table. + + Column alias injection is needed in the following query (which + most likely will fail): + + sess.createSQLQuery("SELECT c.*, m.* FROM CATS c, CATS m WHERE c.MOTHER_ID = c.ID") + .addEntity("cat", Cat.class) + .addEntity("mother", Cat.class) + + + The query was intended to return two Cat instances per row: a cat + and its mother. The query will, however, fail because there is a + conflict of names; the instances are mapped to the same column names. + Also, on some databases the returned column aliases will most likely be + on the form "c.ID", "c.NAME", etc. which are not equal to the columns + specified in the mappings ("ID" and "NAME"). + + The following form is not vulnerable to column name + duplication: + + sess.createSQLQuery("SELECT {cat.*}, {m.*} FROM CATS c, CATS m WHERE c.MOTHER_ID = m.ID") + .addEntity("cat", Cat.class) + .addEntity("mother", Cat.class) + + + This query specified: + + + + the SQL query string, with placeholders for Hibernate to + inject column aliases + + + + the entities returned by the query + + + + The {cat.*} and {mother.*} notation used above is a shorthand for + "all properties". Alternatively, you can list the columns explicitly, + but even in this case Hibernate injects the SQL column aliases for each + property. The placeholder for a column alias is just the property name + qualified by the table alias. In the following example, you retrieve + Cats and their mothers from a different table (cat_log) to the one + declared in the mapping metadata. You can even use the property aliases + in the where clause. + + String sql = "SELECT ID as {c.id}, NAME as {c.name}, " + + "BIRTHDATE as {c.birthDate}, MOTHER_ID as {c.mother}, {mother.*} " + + "FROM CAT_LOG c, CAT_LOG m WHERE {c.mother} = c.ID"; + +List loggedCats = sess.createSQLQuery(sql) + .addEntity("cat", Cat.class) + .addEntity("mother", Cat.class).list() + + +
+ Alias and property references + + In most cases the above alias injection is needed. For queries + relating to more complex mappings, like composite properties, + inheritance discriminators, collections etc., you can use specific + aliases that allow Hibernate to inject the proper aliases. + + The following table shows the different ways you can use the + alias injection. Please note that the alias names in the result are + simply examples; each alias will have a unique and probably different + name when used. + + + Alias injection names + + + + + + + + + + + Description + + Syntax + + Example + + + + + + A simple property + + {[aliasname].[propertyname] + + A_NAME as {item.name} + + + + A composite property + + {[aliasname].[componentname].[propertyname]} + + CURRENCY as {item.amount.currency}, VALUE as + {item.amount.value} + + + + Discriminator of an entity + + {[aliasname].class} + + DISC as {item.class} + + + + All properties of an entity + + {[aliasname].*} + + {item.*} + + + + A collection key + + {[aliasname].key} + + ORGID as {coll.key} + + + + The id of an collection + + {[aliasname].id} + + EMPID as {coll.id} + + + + The element of an collection + + {[aliasname].element} + + XID as {coll.element} + + + + property of the element in the collection + + {[aliasname].element.[propertyname]} + + NAME as {coll.element.name} + + + + All properties of the element in the collection + + {[aliasname].element.*} + + {coll.element.*} + + + + All properties of the collection + + {[aliasname].*} + + {coll.*} + + + +
+
+
+ +
+ Returning non-managed entities + + It is possible to apply a ResultTransformer to native SQL queries, + allowing it to return non-managed entities. + + sess.createSQLQuery("SELECT NAME, BIRTHDATE FROM CATS") + .setResultTransformer(Transformers.aliasToBean(CatDTO.class)) + + This query specified: + + + + the SQL query string + + + + a result transformer + + + + The above query will return a list of CatDTO + which has been instantiated and injected the values of NAME and + BIRTHNAME into its corresponding properties or fields. +
+ +
+ Handling inheritance + + Native SQL queries which query for entities that are mapped as + part of an inheritance must include all properties for the baseclass and + all its subclasses. +
+ +
+ Parameters + + Native SQL queries support positional as well as named + parameters: + + Query query = sess.createSQLQuery("SELECT * FROM CATS WHERE NAME like ?").addEntity(Cat.class); +List pusList = query.setString(0, "Pus%").list(); + +query = sess.createSQLQuery("SELECT * FROM CATS WHERE NAME like :name").addEntity(Cat.class); +List pusList = query.setString("name", "Pus%").list(); +
+
+ +
+ Named SQL queries + + Named SQL queries can also be defined in the mapping document and + called in exactly the same way as a named HQL query. In this case, you do + not need to call + addEntity(). + + + Named sql query using the <sql-query> maping + element + + <sql-query name="persons"> + <return alias="person" class="eg.Person"/> + SELECT person.NAME AS {person.name}, + person.AGE AS {person.age}, + person.SEX AS {person.sex} + FROM PERSON person + WHERE person.NAME LIKE :namePattern +</sql-query> + + + + Execution of a named query + + List people = sess.getNamedQuery("persons") + .setString("namePattern", namePattern) + .setMaxResults(50) + .list(); + + + The <return-join> element is use to join + associations and the <load-collection> element is + used to define queries which initialize collections, + + + Named sql query with association + + <sql-query name="personsWith"> + <return alias="person" class="eg.Person"/> + <return-join alias="address" property="person.mailingAddress"/> + SELECT person.NAME AS {person.name}, + person.AGE AS {person.age}, + person.SEX AS {person.sex}, + address.STREET AS {address.street}, + address.CITY AS {address.city}, + address.STATE AS {address.state}, + address.ZIP AS {address.zip} + FROM PERSON person + JOIN ADDRESS address + ON person.ID = address.PERSON_ID AND address.TYPE='MAILING' + WHERE person.NAME LIKE :namePattern +</sql-query> + + + A named SQL query may return a scalar value. You must declare the + column alias and Hibernate type using the + <return-scalar> element: + + + Named query returning a scalar + + <sql-query name="mySqlQuery"> + <return-scalar column="name" type="string"/> + <return-scalar column="age" type="long"/> + SELECT p.NAME AS name, + p.AGE AS age, + FROM PERSON p WHERE p.NAME LIKE 'Hiber%' +</sql-query> + + + You can externalize the resultset mapping information in a + <resultset> element which will allow you to + either reuse them across several named queries or through the + setResultSetMapping() API. + + + <resultset> mapping used to externalize mapping + information + + <resultset name="personAddress"> + <return alias="person" class="eg.Person"/> + <return-join alias="address" property="person.mailingAddress"/> +</resultset> + +<sql-query name="personsWith" resultset-ref="personAddress"> + SELECT person.NAME AS {person.name}, + person.AGE AS {person.age}, + person.SEX AS {person.sex}, + address.STREET AS {address.street}, + address.CITY AS {address.city}, + address.STATE AS {address.state}, + address.ZIP AS {address.zip} + FROM PERSON person + JOIN ADDRESS address + ON person.ID = address.PERSON_ID AND address.TYPE='MAILING' + WHERE person.NAME LIKE :namePattern +</sql-query> + + + You can, alternatively, use the resultset mapping information in + your hbm files directly in java code. + + + Programmatically specifying the result mapping information + + + List cats = sess.createSQLQuery( + "select {cat.*}, {kitten.*} from cats cat, cats kitten where kitten.mother = cat.id" + ) + .setResultSetMapping("catAndKitten") + .list(); + + + So far we have only looked at externalizing SQL queries using + Hibernate mapping files. The same concept is also available with + anntations and is called named native queries. You can use + @NamedNativeQuery + (@NamedNativeQueries) in conjunction with + @SqlResultSetMapping + (@SqlResultSetMappings). Like + @NamedQuery, @NamedNativeQuery + and @SqlResultSetMapping can be defined at class level, + but their scope is global to the application. Lets look at a view + examples. + + + shows how a resultSetMapping parameter is defined in + @NamedNativeQuery. It represents the name of a defined + @SqlResultSetMapping. The resultset mapping declares + the entities retrieved by this native query. Each field of the entity is + bound to an SQL alias (or column name). All fields of the entity including + the ones of subclasses and the foreign key columns of related entities + have to be present in the SQL query. Field definitions are optional + provided that they map to the same column name as the one declared on the + class property. In the example 2 entities, Night and + Area, are returned and each property is declared and + associated to a column name, actually the column name retrieved by the + query. + + In the result + set mapping is implicit. We only describe the entity class of the result + set mapping. The property / column mappings is done using the entity + mapping values. In this case the model property is bound to the model_txt + column. + + Finally, if the association to a related entity involve a composite + primary key, a @FieldResult element should be used for + each foreign key column. The @FieldResult name is + composed of the property name for the relationship, followed by a dot + ("."), followed by the name or the field or property of the primary key. + This can be seen in . + + + Named SQL query using <classname>@NamedNativeQuery</classname> + together with <classname>@SqlResultSetMapping</classname> + + @NamedNativeQuery(name="night&area", query="select night.id nid, night.night_duration, " + + " night.night_date, area.id aid, night.area_id, area.name " + + "from Night night, Area area where night.area_id = area.id", + resultSetMapping="joinMapping") +@SqlResultSetMapping(name="joinMapping", entities={ + @EntityResult(entityClass=Night.class, fields = { + @FieldResult(name="id", column="nid"), + @FieldResult(name="duration", column="night_duration"), + @FieldResult(name="date", column="night_date"), + @FieldResult(name="area", column="area_id"), + discriminatorColumn="disc" + }), + @EntityResult(entityClass=org.hibernate.test.annotations.query.Area.class, fields = { + @FieldResult(name="id", column="aid"), + @FieldResult(name="name", column="name") + }) + } +) + + + + Implicit result set mapping + + @Entity +@SqlResultSetMapping(name="implicit", + entities=@EntityResult(entityClass=SpaceShip.class)) +@NamedNativeQuery(name="implicitSample", + query="select * from SpaceShip", + resultSetMapping="implicit") +public class SpaceShip { + private String name; + private String model; + private double speed; + + @Id + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + @Column(name="model_txt") + public String getModel() { + return model; + } + + public void setModel(String model) { + this.model = model; + } + + public double getSpeed() { + return speed; + } + + public void setSpeed(double speed) { + this.speed = speed; + } +} + + + + Using dot notation in @FieldResult for specifying associations + + + @Entity +@SqlResultSetMapping(name="compositekey", + entities=@EntityResult(entityClass=SpaceShip.class, + fields = { + @FieldResult(name="name", column = "name"), + @FieldResult(name="model", column = "model"), + @FieldResult(name="speed", column = "speed"), + @FieldResult(name="captain.firstname", column = "firstn"), + @FieldResult(name="captain.lastname", column = "lastn"), + @FieldResult(name="dimensions.length", column = "length"), + @FieldResult(name="dimensions.width", column = "width") + }), + columns = { @ColumnResult(name = "surface"), + @ColumnResult(name = "volume") } ) + +@NamedNativeQuery(name="compositekey", + query="select name, model, speed, lname as lastn, fname as firstn, length, width, length * width as surface from SpaceShip", + resultSetMapping="compositekey") +} ) +public class SpaceShip { + private String name; + private String model; + private double speed; + private Captain captain; + private Dimensions dimensions; + + @Id + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + @ManyToOne(fetch= FetchType.LAZY) + @JoinColumns( { + @JoinColumn(name="fname", referencedColumnName = "firstname"), + @JoinColumn(name="lname", referencedColumnName = "lastname") + } ) + public Captain getCaptain() { + return captain; + } + + public void setCaptain(Captain captain) { + this.captain = captain; + } + + public String getModel() { + return model; + } + + public void setModel(String model) { + this.model = model; + } + + public double getSpeed() { + return speed; + } + + public void setSpeed(double speed) { + this.speed = speed; + } + + public Dimensions getDimensions() { + return dimensions; + } + + public void setDimensions(Dimensions dimensions) { + this.dimensions = dimensions; + } +} + +@Entity +@IdClass(Identity.class) +public class Captain implements Serializable { + private String firstname; + private String lastname; + + @Id + public String getFirstname() { + return firstname; + } + + public void setFirstname(String firstname) { + this.firstname = firstname; + } + + @Id + public String getLastname() { + return lastname; + } + + public void setLastname(String lastname) { + this.lastname = lastname; + } +} + + + + + If you retrieve a single entity using the default mapping, you can + specify the resultClass attribute instead of + resultSetMapping: + + @NamedNativeQuery(name="implicitSample", query="select * from SpaceShip", resultClass=SpaceShip.class) +public class SpaceShip { + + + In some of your native queries, you'll have to return scalar values, + for example when building report queries. You can map them in the + @SqlResultsetMapping through + @ColumnResult. You actually can even mix, entities and + scalar returns in the same native query (this is probably not that common + though). + + + Scalar values via <classname>@ColumnResult</classname> + + @SqlResultSetMapping(name="scalar", columns=@ColumnResult(name="dimension")) +@NamedNativeQuery(name="scalar", query="select length*width as dimension from SpaceShip", resultSetMapping="scalar") + + + An other query hint specific to native queries has been introduced: + org.hibernate.callable which can be true or false + depending on whether the query is a stored procedure or not. + +
+ Using return-property to explicitly specify column/alias + names + + You can explicitly tell Hibernate what column aliases to use with + <return-property>, instead of using the + {}-syntax to let Hibernate inject its own aliases.For + example: + + <sql-query name="mySqlQuery"> + <return alias="person" class="eg.Person"> + <return-property name="name" column="myName"/> + <return-property name="age" column="myAge"/> + <return-property name="sex" column="mySex"/> + </return> + SELECT person.NAME AS myName, + person.AGE AS myAge, + person.SEX AS mySex, + FROM PERSON person WHERE person.NAME LIKE :name +</sql-query> + + + <return-property> also works with + multiple columns. This solves a limitation with the + {}-syntax which cannot allow fine grained control of + multi-column properties. + + <sql-query name="organizationCurrentEmployments"> + <return alias="emp" class="Employment"> + <return-property name="salary"> + <return-column name="VALUE"/> + <return-column name="CURRENCY"/> + </return-property> + <return-property name="endDate" column="myEndDate"/> + </return> + SELECT EMPLOYEE AS {emp.employee}, EMPLOYER AS {emp.employer}, + STARTDATE AS {emp.startDate}, ENDDATE AS {emp.endDate}, + REGIONCODE as {emp.regionCode}, EID AS {emp.id}, VALUE, CURRENCY + FROM EMPLOYMENT + WHERE EMPLOYER = :id AND ENDDATE IS NULL + ORDER BY STARTDATE ASC +</sql-query> + + In this example <return-property> was + used in combination with the {}-syntax for injection. + This allows users to choose how they want to refer column and + properties. + + If your mapping has a discriminator you must use + <return-discriminator> to specify the + discriminator column. +
+ +
+ Using stored procedures for querying + + Hibernate provides support for queries via stored procedures and + functions. Most of the following documentation is equivalent for both. + The stored procedure/function must return a resultset as the first + out-parameter to be able to work with Hibernate. An example of such a + stored function in Oracle 9 and higher is as follows: + + CREATE OR REPLACE FUNCTION selectAllEmployments + RETURN SYS_REFCURSOR +AS + st_cursor SYS_REFCURSOR; +BEGIN + OPEN st_cursor FOR + SELECT EMPLOYEE, EMPLOYER, + STARTDATE, ENDDATE, + REGIONCODE, EID, VALUE, CURRENCY + FROM EMPLOYMENT; + RETURN st_cursor; + END; + + To use this query in Hibernate you need to map it via a named + query. + + <sql-query name="selectAllEmployees_SP" callable="true"> + <return alias="emp" class="Employment"> + <return-property name="employee" column="EMPLOYEE"/> + <return-property name="employer" column="EMPLOYER"/> + <return-property name="startDate" column="STARTDATE"/> + <return-property name="endDate" column="ENDDATE"/> + <return-property name="regionCode" column="REGIONCODE"/> + <return-property name="id" column="EID"/> + <return-property name="salary"> + <return-column name="VALUE"/> + <return-column name="CURRENCY"/> + </return-property> + </return> + { ? = call selectAllEmployments() } +</sql-query> + + Stored procedures currently only return scalars and entities. + <return-join> and + <load-collection> are not supported. + +
+ Rules/limitations for using stored procedures + + You cannot use stored procedures with Hibernate unless you + follow some procedure/function rules. If they do not follow those + rules they are not usable with Hibernate. If you still want to use + these procedures you have to execute them via + session.connection(). The rules are different for + each database, since database vendors have different stored procedure + semantics/syntax. + + Stored procedure queries cannot be paged with + setFirstResult()/setMaxResults(). + + The recommended call form is standard SQL92: { ? = call + functionName(<parameters>) } or { ? = call + procedureName(<parameters>}. Native call syntax is not + supported. + + For Oracle the following rules apply: + + + + A function must return a result set. The first parameter of + a procedure must be an OUT that returns a + result set. This is done by using a + SYS_REFCURSOR type in Oracle 9 or 10. In Oracle + you need to define a REF CURSOR type. See + Oracle literature for further information. + + + + For Sybase or MS SQL server the following rules apply: + + + + The procedure must return a result set. Note that since + these servers can return multiple result sets and update counts, + Hibernate will iterate the results and take the first result that + is a result set as its return value. Everything else will be + discarded. + + + + If you can enable SET NOCOUNT ON in your + procedure it will probably be more efficient, but this is not a + requirement. + + +
+
+
+ +
+ Custom SQL for create, update and delete + + Hibernate can use custom SQL for create, update, and delete + operations. The SQL can be overridden at the statement level or + inidividual column level. This section describes statement overrides. For + columns, see . shows how to define + custom SQL operatons using annotations. + + + Custom CRUD via annotations + + @Entity +@Table(name="CHAOS") +@SQLInsert( sql="INSERT INTO CHAOS(size, name, nickname, id) VALUES(?,upper(?),?,?)") +@SQLUpdate( sql="UPDATE CHAOS SET size = ?, name = upper(?), nickname = ? WHERE id = ?") +@SQLDelete( sql="DELETE CHAOS WHERE id = ?") +@SQLDeleteAll( sql="DELETE CHAOS") +@Loader(namedQuery = "chaos") +@NamedNativeQuery(name="chaos", query="select id, size, name, lower( nickname ) as nickname from CHAOS where id= ?", resultClass = Chaos.class) +public class Chaos { + @Id + private Long id; + private Long size; + private String name; + private String nickname; + + + @SQLInsert, @SQLUpdate, + @SQLDelete, @SQLDeleteAll + respectively override the INSERT, UPDATE, DELETE, and DELETE all + statement. The same can be achieved using Hibernate mapping files and the + <sql-insert>, + <sql-update> and + <sql-delete> nodes. This can be seen in . + + + Custom CRUD XML + + <class name="Person"> + <id name="id"> + <generator class="increment"/> + </id> + <property name="name" not-null="true"/> + <sql-insert>INSERT INTO PERSON (NAME, ID) VALUES ( UPPER(?), ? )</sql-insert> + <sql-update>UPDATE PERSON SET NAME=UPPER(?) WHERE ID=?</sql-update> + <sql-delete>DELETE FROM PERSON WHERE ID=?</sql-delete> +</class> + + + If you expect to call a store procedure, be sure to set the + callable attribute to true. In + annotations as well as in xml. + + To check that the execution happens correctly, Hibernate allows you + to define one of those three strategies: + + + + none: no check is performed: the store procedure is expected to + fail upon issues + + + + count: use of rowcount to check that the update is + successful + + + + param: like COUNT but using an output parameter rather that the + standard mechanism + + + + To define the result check style, use the check + parameter which is again available in annoations as well as in xml. + + You can use the exact same set of annotations respectively xml nodes + to override the collection related statements -see . + + + Overriding SQL statements for collections using + annotations + + @OneToMany +@JoinColumn(name="chaos_fk") +@SQLInsert( sql="UPDATE CASIMIR_PARTICULE SET chaos_fk = ? where id = ?") +@SQLDelete( sql="UPDATE CASIMIR_PARTICULE SET chaos_fk = null where id = ?") +private Set<CasimirParticle> particles = new HashSet<CasimirParticle>(); + + + + The parameter order is important and is defined by the order + Hibernate handles properties. You can see the expected order by enabling + debug logging for the org.hibernate.persister.entity + level. With this level enabled Hibernate will print out the static SQL + that is used to create, update, delete etc. entities. (To see the + expected sequence, remember to not include your custom SQL through + annotations or mapping files as that will override the Hibernate + generated static sql) + + + Overriding SQL statements for secondary tables is also possible + using @org.hibernate.annotations.Table and either (or + all) attributes sqlInsert, + sqlUpdate, sqlDelete: + + + Overriding SQL statements for secondary tables + + @Entity +@SecondaryTables({ + @SecondaryTable(name = "`Cat nbr1`"), + @SecondaryTable(name = "Cat2"}) +@org.hibernate.annotations.Tables( { + @Table(appliesTo = "Cat", comment = "My cat table" ), + @Table(appliesTo = "Cat2", foreignKey = @ForeignKey(name="FK_CAT2_CAT"), fetch = FetchMode.SELECT, + sqlInsert=@SQLInsert(sql="insert into Cat2(storyPart2, id) values(upper(?), ?)") ) +} ) +public class Cat implements Serializable { + + + The previous example also shows that you can give a comment to a + given table (primary or secondary): This comment will be used for DDL + generation. + + + The SQL is directly executed in your database, so you can use any + dialect you like. This will, however, reduce the portability of your + mapping if you use database specific SQL. + + + Last but not least, stored procedures are in most cases required to + return the number of rows inserted, updated and deleted. Hibernate always + registers the first statement parameter as a numeric output parameter for + the CUD operations: + + + Stored procedures and their return value + + CREATE OR REPLACE FUNCTION updatePerson (uid IN NUMBER, uname IN VARCHAR2) + RETURN NUMBER IS +BEGIN + + update PERSON + set + NAME = uname, + where + ID = uid; + + return SQL%ROWCOUNT; + +END updatePerson; + +
+ +
+ Custom SQL for loading + + You can also declare your own SQL (or HQL) queries for entity + loading. As with inserts, updates, and deletes, this can be done at the + individual column level as described in or at the statement level. Here + is an example of a statement level override: + + <sql-query name="person"> + <return alias="pers" class="Person" lock-mode="upgrade"/> + SELECT NAME AS {pers.name}, ID AS {pers.id} + FROM PERSON + WHERE ID=? + FOR UPDATE +</sql-query> + + This is just a named query declaration, as discussed earlier. You + can reference this named query in a class mapping: + + <class name="Person"> + <id name="id"> + <generator class="increment"/> + </id> + <property name="name" not-null="true"/> + <loader query-ref="person"/> +</class> + + This even works with stored procedures. + + You can even define a query for collection loading: + + <set name="employments" inverse="true"> + <key/> + <one-to-many class="Employment"/> + <loader query-ref="employments"/> +</set> + + <sql-query name="employments"> + <load-collection alias="emp" role="Person.employments"/> + SELECT {emp.*} + FROM EMPLOYMENT emp + WHERE EMPLOYER = :id + ORDER BY STARTDATE ASC, EMPLOYEE ASC +</sql-query> + + You can also define an entity loader that loads a collection by join + fetching: + + <sql-query name="person"> + <return alias="pers" class="Person"/> + <return-join alias="emp" property="pers.employments"/> + SELECT NAME AS {pers.*}, {emp.*} + FROM PERSON pers + LEFT OUTER JOIN EMPLOYMENT emp + ON pers.ID = emp.PERSON_ID + WHERE ID=? +</sql-query> + + The annotation equivalent <loader> is the + @Loader annotation as seen in . +
+ +
diff --git a/documentation/status.md b/documentation/status.md index c4ae84f89d..8f61d18b48 100644 --- a/documentation/status.md +++ b/documentation/status.md @@ -21,15 +21,16 @@ Covers reference topics targeting users. * Database_Access * Transactions * JNDI -* Fetching (needs some work) +* Fetching (needs some work) - document batch fetching, subselect fetching, extra laziness and EntityGraphs +* Flushing (to be written) * Cascading (needs lots of work) * Locking (needs some work) * Batching (needs lot of work - not started - open questions) * Caching (needs some work) * Events (need some work) -* HQL_JPQL (needs lots of work) -* Criteria (needs lots of work) -* Native_Queries (needs lots of work) +* Query - HQL/JPQL (needs lots of work) +* Query - Criteria +* Query - Native (copy from old) * Multi_Tenancy (needs some work) * OSGi (right place for this?) * Envers (right place for this?)