SlideShare a Scribd company logo
Queries The Hibernate object-oriented query facilities
Hibernate query options The Hibernate Query Language (HQL): The Criteria API for type-safe queries: Direct SQL with Hibernate mapping: session. createQuery (" from Category cat where cat.name like '%Flights' ").list(); session. createCriteria (Category.class) .add( Expression.like("name", "%Flights") ) .list(); session. createSQLQuery ( " select {cat.*} from CATEGORY {cat} where NAME like '%Flights' ", "cat", Category.class) .list();
Executing queries We execute queries with the Query  object from  createQuery()  and  createSQLQuery() Criteria  object from  createCriteria() Pagination: Getting a list or results, or a single result: Iterating: Query q = session.createQuery("from User user order by user.name asc") .setFirstResult(30) .setMaxResults(10) .list(); List result = q. list (); Object o = q.setMaxResults(1). uniqueResult (); Iterator it = q. iterate ();
Executing queries A  ScrollableResults  let’s us step through the query results, just like a JDBC scrollable  ResultSet : ScrollableResults  users = session.createQuery( "from User user order by user.name asc") .scroll(); while ( users.next() ) { User user = results.get(0); … }   users.close();
Binding parameters We should never use String manipulation: We use  named parameter binding : Positional parameters are not recommended: String queryString = "from Item i where i.description like '"  + string +  "'"; List result = session.createQuery(queryString).list(); String queryString = "from Item item " + "where item.description like  :searchString  " + "and item.date >  :minDate "; List result = session.createQuery(queryString) . setString ("searchString",  searchString ) . setDate ("minDate",  minDate ) .list(); String queryString = "from Item item where item.description like  ? "; Query q = session.createQuery(queryString). setString ( 0 , searchString);
More parameter binding techniques Use  setEntity()  to bind a persistent entity: Use  setProperties()  to bind properties of a JavaBean to several named parameters simultaneously: Use  setParameterList()  to bind multiple values: session.createQuery("from Item item where item.seller = :seller") .setEntity("seller", seller) ; Item item = new Item(); item. setSeller (seller); item. setDescription (description); String queryString = "from Item item " + "where item.seller =  :seller  and " + "item.description like  :description "; session.createQuery(queryString). setProperties (item).list(); session.createQuery("from Item item where item.id in (:idList)") .setParameterList(“idList", idList) ;
Externalizing named queries We can execute a  named query : The query is defined in the mapping metadata: We can also name SQL queries: Query q = session.getNamedQuery(&quot; findItemsByDescription &quot;)   .setString(&quot;description&quot;, description); <query name=&quot; findItemsByDescription &quot;><![CDATA[   from Item item where item.description like :description ]]></query> <sql-query name=&quot; findItemsByDescription &quot;><![CDATA[ select {item.*} from item where description like :description ]]> <return alias=&quot;item&quot; class=&quot;Item&quot;/> </sql-query>
Basic queries in HQL and with Criteria The simplest query: Using an alias: Polymorphic queries: from Bid from BillingDetails from CreditCard from java.lang.Object // Returns all persistent objects! from Bid as bid session.createCriteria(Bid.class) session.createCriteria(BillingDetails.class)
Restriction Restriction with a  where  clause in HQL: Using a  Criterion : All regular SQL operators are supported in expressions: from User user  where user.email = 'foo@hibernate.org' Criterion  emailEq  = Expression.eq(&quot;email&quot;, &quot;foo@hibernate.org); Criteria crit = session.createCriteria(User.class); crit.add( emailEq ); User user = (User) crit.uniqueResult(); from User user where user.email  =  'foo@hibernate.org' and  user.firstname  like  'Max%' and  user.lastname  is not null or  user.signupDate  <  :mondayLastWeek
String matching We can use wildcards for string pattern matching: The Criteria API allows string matching without string manipulation: We can also call arbitrary SQL functions in the  where  clause: from User user where user.firstname not like &quot; %Foo B% &quot; session.createCriteria(User.class) .add( Expression.like(&quot;firstname&quot;, &quot;G&quot;,  MatchMode.START ) ); from User user where  lower(user.email)  = 'foo@hibernate.org' session.createCriteria(User.class) .add( Expression.eq(&quot;email&quot;, &quot;foo@hibernate.org&quot;). ignoreCase()  ) );
Ordering results The order by clause is used in HQL: The Criteria API also supports ordering of results: HQL and the Criteria API give you all the power of SQL without falling back to table and column names. from User user  order by user.username desc List results = session.createCriteria(User.class) .addOrder(  Order.asc (&quot;lastname&quot;) ) .addOrder(  Order.asc (&quot;firstname&quot;) ) .list(); from Item item  order by item.successfulBid.amount desc, item.id asc
Joining associations The join SQL operation combines the data from two tables: PRICE PRICE 3 Baz 1.00 NAME ITEM_ID 1 1 2 Foo Foo Bar 2.00 2.00 50.00 from ITEM I  inner join  BID B on I.ITEM_ID = B.ITEM_ID AMOUNT ITEM_ID BID_ID 1 2 3 1 1 2 10.00 20.00 55.00 NAME ITEM_ID 1 1 2 Foo Foo Bar 2.00 2.00 50.00 from ITEM I  left outer join  BID B on I.ITEM_ID = B.ITEM_ID AMOUNT ITEM_ID BID_ID 1 2 3 1 1 2 10.00 20.00 55.00 null null null
Fetching associations in Hibernate We can fetch associated objects in HQL: For all  Item s returned, the  item.bids  collection is fully initialized, all with a single SQL outer join query. We may only fetch one collection in one HQL query, preserving performance in SQL. We can also use a Criteria: from Item item left join fetch  item.bids where item.description like '%gc%' session.createCriteria(Item.class) .setFetchMode(&quot;bids&quot;, FetchMode.EAGER) .add( Expression.like(&quot;description&quot;, &quot;gc&quot;, MatchMode.ANYWHERE) )
Fetching single-ended associations We can also initialize (fetch) single-ended associations: IMPORTANT: HQL always ignores the  outer-join  setting in the mapping metadata, we have to use an  explicit  fetch join. The Criteria  will not ignore  the metadata, disable it with  FetchMode.LAZY ! from Bid bid left join fetch  bid.item left join fetch  bid.bidder where bid.amount > 100 session.createCriteria(Bid.class) .setFetchMode(&quot;item&quot;, FetchMode.EAGER) .setFetchMode(&quot;bidder&quot;, FetchMode.EAGER) .add( Expression.gt(&quot;amount&quot;, new Float(100) ) )
Using aliases with joins We need an alias to express restrictions on joined objects: This query returns ordered pairs of Items and Bids: The select clause is optional: from Item item join item.bids   bid where item.description like '%gc%' and  bid .amount > 100 Query q = session.createQuery(&quot; from Item item join item.bids bid &quot;); Iterator pairs = q.list().iterator(); while ( pairs.hasNext() ) { Object[] pair  = (Object[]) pairs.next(); Item item = (Item) pair[0]; Bid bid = (Bid) pair[1]; } select item  from Item item join item.bids bid where bid.amount > 100
Using implicit association joins We can query components (dereference with a dot): We can join single-ended associations implicitly: We have to be careful (how many SQL joins is this?): from User user where user . address . city = 'Bangkok' from Bid bid where bid . item . description like '%gc%' from Bid bid where bid.item.category.name like 'Laptop%' from Bid bid where bid.item.category.name like 'Laptop%' and bid.item.successfulBid.amount > 100
Theta-style joins First, we create a Cartesian Product: Then, we add a join condition in the  where  clause: Theta-style (inner) joins are used when related tables (classes) are not referenced with a foreign key relationship (no automatic joining). from User, LogRecord from User user, LogRecord log  where user.username = log.username
Report queries in HQL The  select  clause is used for projection: The result may be an  Object[]  of non-transactional objects: Dynamic instantiation is much easier to handle: select item  from Item item join item.bids bid where bid.amount > 100 select item.id, item.description, bid.amount from Item item join item.bids bid where bid.amount > 100 select new ItemRow ( item.id, item.description, bid.amount ) from Item item join item.bids bid where bid.amount > 100
Aggregation in HQL The aggregation functions are count() ,  min() ,  max() ,  sum()  and  avg() Count all items with a successful bid: The total of all successful bids: The result is an ordered pair of  Float s: select  count (item.successfulBid) from Item item select  sum (item.successfulBid.amount) from Item item select  min (bid.amount),  max (bid.amount) from Bid bid where bid.item.id = 1
Grouping in HQL If we aggregate, we have to group every property in the  select : We can further restrict the result on the group: Use report queries (projection, aggregation, grouping, dynamic instantiation) to optimize performance, only retrieve required data. select  bid.item.id , avg(bid.amount) from Bid bid group by   bid.item.id select  item.id , count(bid) ), avg(bid.amount) from Item item join item.bids bid where item.successfulBid is null group by  item.id having count(bid) > 10
Dynamic queries with Query By Example Complex searches are best expressed with a QBE query: QBE can be combined with QBC: User  exampleUser  = new User(); exampleUser.setFirstname (&quot;Max&quot;); exampleUser.setEmail (&quot;@hibernate.org&quot;); List result = findUsers( exampleUser ); public List  findUsers(User user)  throws HibernateException { return getSession().createCriteria(User.class) .add(  Example.create(user) .ignoreCase().enableLik (MatchMode.ANYWHERE) ) .list(); } createCriteria(User.class) .add(  Example.create(user) .ignoreCase().enableLike(MatchMode.ANYWHERE) ) . createCriteria(&quot;items&quot;) .add(  Expression.isNull(&quot;successfulBid&quot;)  );
Filtering persistent collections We can filter the collection of bids of an already loaded  Item : HQL filter queries have an implicit  from  and  where  clause: A filter doesn't have to return objects from the collection: Query q =  session.createFilter (  item.getBids() , &quot;order by  this .amount asc&quot; ); Query q = session.createFilter( item.getBids(),  &quot;&quot;  );  // This is valid... List result = q.setFirstResult(50).setMaxResults(100).list() // and useful! List results = session.createFilter( item.getBids(), &quot;select  elements (this.bidder.bids)&quot; ).list()
Subqueries in HQL Correlated subquery, total items sold by users, if more than 10: Uncorrelated subquery, all bids that are 1 within the maximum: We can use SQL quantifiers,  ANY / ALL / SOME / IN: from User user where 10 < ( select count(item) from user.items where item.successfulBid is not null ) from Bid bid where bid.amount + 1 >= ( select max(b.amount) from Bid b ) from Item item where 100 >  all  ( select b.amount from item.bids b ) from Item item where 100 <  any  ( select b.amount from item.bids b ) from Item item where 100 =  some  ( select b.amount from item.bids b ) from Item item where 100  in  ( select b.amount from item.bids b )
Native SQL queries Direct native SQL queries use Hibernate shortcuts: We can return  Object[] s (tuples): We can externalize SQL queries to the mapping file: List results = session.createSQLQuery(&quot;select  {uzer.*}  from user uzer&quot;,  &quot; uzer &quot;,  User.class ).list(); List tuples = session.createSQLQuery( &quot;select {u.*}, {b.*} from user u inner join bid b where u.id = b.bidder_id&quot;, new String[] { &quot;u&quot;, &quot;b&quot; }, new Class[] {User.class, Bid.class} ).list(); <sql-query name=&quot;findUsersAndBids&quot;><![CDATA[ select {u.*}, {b.*} from user u inner join bid b where u.id = b.bidder_id ]]> <return alias=&quot;u&quot; class=&quot;User&quot;/> <return alias=&quot;b&quot; class=&quot;Bid&quot;/> </sql-query>

More Related Content

08 Queries

  • 1. Queries The Hibernate object-oriented query facilities
  • 2. Hibernate query options The Hibernate Query Language (HQL): The Criteria API for type-safe queries: Direct SQL with Hibernate mapping: session. createQuery (&quot; from Category cat where cat.name like '%Flights' &quot;).list(); session. createCriteria (Category.class) .add( Expression.like(&quot;name&quot;, &quot;%Flights&quot;) ) .list(); session. createSQLQuery ( &quot; select {cat.*} from CATEGORY {cat} where NAME like '%Flights' &quot;, &quot;cat&quot;, Category.class) .list();
  • 3. Executing queries We execute queries with the Query object from createQuery() and createSQLQuery() Criteria object from createCriteria() Pagination: Getting a list or results, or a single result: Iterating: Query q = session.createQuery(&quot;from User user order by user.name asc&quot;) .setFirstResult(30) .setMaxResults(10) .list(); List result = q. list (); Object o = q.setMaxResults(1). uniqueResult (); Iterator it = q. iterate ();
  • 4. Executing queries A ScrollableResults let’s us step through the query results, just like a JDBC scrollable ResultSet : ScrollableResults users = session.createQuery( &quot;from User user order by user.name asc&quot;) .scroll(); while ( users.next() ) { User user = results.get(0); … } users.close();
  • 5. Binding parameters We should never use String manipulation: We use named parameter binding : Positional parameters are not recommended: String queryString = &quot;from Item i where i.description like '&quot; + string + &quot;'&quot;; List result = session.createQuery(queryString).list(); String queryString = &quot;from Item item &quot; + &quot;where item.description like :searchString &quot; + &quot;and item.date > :minDate &quot;; List result = session.createQuery(queryString) . setString (&quot;searchString&quot;, searchString ) . setDate (&quot;minDate&quot;, minDate ) .list(); String queryString = &quot;from Item item where item.description like ? &quot;; Query q = session.createQuery(queryString). setString ( 0 , searchString);
  • 6. More parameter binding techniques Use setEntity() to bind a persistent entity: Use setProperties() to bind properties of a JavaBean to several named parameters simultaneously: Use setParameterList() to bind multiple values: session.createQuery(&quot;from Item item where item.seller = :seller&quot;) .setEntity(&quot;seller&quot;, seller) ; Item item = new Item(); item. setSeller (seller); item. setDescription (description); String queryString = &quot;from Item item &quot; + &quot;where item.seller = :seller and &quot; + &quot;item.description like :description &quot;; session.createQuery(queryString). setProperties (item).list(); session.createQuery(&quot;from Item item where item.id in (:idList)&quot;) .setParameterList(“idList&quot;, idList) ;
  • 7. Externalizing named queries We can execute a named query : The query is defined in the mapping metadata: We can also name SQL queries: Query q = session.getNamedQuery(&quot; findItemsByDescription &quot;) .setString(&quot;description&quot;, description); <query name=&quot; findItemsByDescription &quot;><![CDATA[ from Item item where item.description like :description ]]></query> <sql-query name=&quot; findItemsByDescription &quot;><![CDATA[ select {item.*} from item where description like :description ]]> <return alias=&quot;item&quot; class=&quot;Item&quot;/> </sql-query>
  • 8. Basic queries in HQL and with Criteria The simplest query: Using an alias: Polymorphic queries: from Bid from BillingDetails from CreditCard from java.lang.Object // Returns all persistent objects! from Bid as bid session.createCriteria(Bid.class) session.createCriteria(BillingDetails.class)
  • 9. Restriction Restriction with a where clause in HQL: Using a Criterion : All regular SQL operators are supported in expressions: from User user where user.email = 'foo@hibernate.org' Criterion emailEq = Expression.eq(&quot;email&quot;, &quot;foo@hibernate.org); Criteria crit = session.createCriteria(User.class); crit.add( emailEq ); User user = (User) crit.uniqueResult(); from User user where user.email = 'foo@hibernate.org' and user.firstname like 'Max%' and user.lastname is not null or user.signupDate < :mondayLastWeek
  • 10. String matching We can use wildcards for string pattern matching: The Criteria API allows string matching without string manipulation: We can also call arbitrary SQL functions in the where clause: from User user where user.firstname not like &quot; %Foo B% &quot; session.createCriteria(User.class) .add( Expression.like(&quot;firstname&quot;, &quot;G&quot;, MatchMode.START ) ); from User user where lower(user.email) = 'foo@hibernate.org' session.createCriteria(User.class) .add( Expression.eq(&quot;email&quot;, &quot;foo@hibernate.org&quot;). ignoreCase() ) );
  • 11. Ordering results The order by clause is used in HQL: The Criteria API also supports ordering of results: HQL and the Criteria API give you all the power of SQL without falling back to table and column names. from User user order by user.username desc List results = session.createCriteria(User.class) .addOrder( Order.asc (&quot;lastname&quot;) ) .addOrder( Order.asc (&quot;firstname&quot;) ) .list(); from Item item order by item.successfulBid.amount desc, item.id asc
  • 12. Joining associations The join SQL operation combines the data from two tables: PRICE PRICE 3 Baz 1.00 NAME ITEM_ID 1 1 2 Foo Foo Bar 2.00 2.00 50.00 from ITEM I inner join BID B on I.ITEM_ID = B.ITEM_ID AMOUNT ITEM_ID BID_ID 1 2 3 1 1 2 10.00 20.00 55.00 NAME ITEM_ID 1 1 2 Foo Foo Bar 2.00 2.00 50.00 from ITEM I left outer join BID B on I.ITEM_ID = B.ITEM_ID AMOUNT ITEM_ID BID_ID 1 2 3 1 1 2 10.00 20.00 55.00 null null null
  • 13. Fetching associations in Hibernate We can fetch associated objects in HQL: For all Item s returned, the item.bids collection is fully initialized, all with a single SQL outer join query. We may only fetch one collection in one HQL query, preserving performance in SQL. We can also use a Criteria: from Item item left join fetch item.bids where item.description like '%gc%' session.createCriteria(Item.class) .setFetchMode(&quot;bids&quot;, FetchMode.EAGER) .add( Expression.like(&quot;description&quot;, &quot;gc&quot;, MatchMode.ANYWHERE) )
  • 14. Fetching single-ended associations We can also initialize (fetch) single-ended associations: IMPORTANT: HQL always ignores the outer-join setting in the mapping metadata, we have to use an explicit fetch join. The Criteria will not ignore the metadata, disable it with FetchMode.LAZY ! from Bid bid left join fetch bid.item left join fetch bid.bidder where bid.amount > 100 session.createCriteria(Bid.class) .setFetchMode(&quot;item&quot;, FetchMode.EAGER) .setFetchMode(&quot;bidder&quot;, FetchMode.EAGER) .add( Expression.gt(&quot;amount&quot;, new Float(100) ) )
  • 15. Using aliases with joins We need an alias to express restrictions on joined objects: This query returns ordered pairs of Items and Bids: The select clause is optional: from Item item join item.bids bid where item.description like '%gc%' and bid .amount > 100 Query q = session.createQuery(&quot; from Item item join item.bids bid &quot;); Iterator pairs = q.list().iterator(); while ( pairs.hasNext() ) { Object[] pair = (Object[]) pairs.next(); Item item = (Item) pair[0]; Bid bid = (Bid) pair[1]; } select item from Item item join item.bids bid where bid.amount > 100
  • 16. Using implicit association joins We can query components (dereference with a dot): We can join single-ended associations implicitly: We have to be careful (how many SQL joins is this?): from User user where user . address . city = 'Bangkok' from Bid bid where bid . item . description like '%gc%' from Bid bid where bid.item.category.name like 'Laptop%' from Bid bid where bid.item.category.name like 'Laptop%' and bid.item.successfulBid.amount > 100
  • 17. Theta-style joins First, we create a Cartesian Product: Then, we add a join condition in the where clause: Theta-style (inner) joins are used when related tables (classes) are not referenced with a foreign key relationship (no automatic joining). from User, LogRecord from User user, LogRecord log where user.username = log.username
  • 18. Report queries in HQL The select clause is used for projection: The result may be an Object[] of non-transactional objects: Dynamic instantiation is much easier to handle: select item from Item item join item.bids bid where bid.amount > 100 select item.id, item.description, bid.amount from Item item join item.bids bid where bid.amount > 100 select new ItemRow ( item.id, item.description, bid.amount ) from Item item join item.bids bid where bid.amount > 100
  • 19. Aggregation in HQL The aggregation functions are count() , min() , max() , sum() and avg() Count all items with a successful bid: The total of all successful bids: The result is an ordered pair of Float s: select count (item.successfulBid) from Item item select sum (item.successfulBid.amount) from Item item select min (bid.amount), max (bid.amount) from Bid bid where bid.item.id = 1
  • 20. Grouping in HQL If we aggregate, we have to group every property in the select : We can further restrict the result on the group: Use report queries (projection, aggregation, grouping, dynamic instantiation) to optimize performance, only retrieve required data. select bid.item.id , avg(bid.amount) from Bid bid group by bid.item.id select item.id , count(bid) ), avg(bid.amount) from Item item join item.bids bid where item.successfulBid is null group by item.id having count(bid) > 10
  • 21. Dynamic queries with Query By Example Complex searches are best expressed with a QBE query: QBE can be combined with QBC: User exampleUser = new User(); exampleUser.setFirstname (&quot;Max&quot;); exampleUser.setEmail (&quot;@hibernate.org&quot;); List result = findUsers( exampleUser ); public List findUsers(User user) throws HibernateException { return getSession().createCriteria(User.class) .add( Example.create(user) .ignoreCase().enableLik (MatchMode.ANYWHERE) ) .list(); } createCriteria(User.class) .add( Example.create(user) .ignoreCase().enableLike(MatchMode.ANYWHERE) ) . createCriteria(&quot;items&quot;) .add( Expression.isNull(&quot;successfulBid&quot;) );
  • 22. Filtering persistent collections We can filter the collection of bids of an already loaded Item : HQL filter queries have an implicit from and where clause: A filter doesn't have to return objects from the collection: Query q = session.createFilter ( item.getBids() , &quot;order by this .amount asc&quot; ); Query q = session.createFilter( item.getBids(), &quot;&quot; ); // This is valid... List result = q.setFirstResult(50).setMaxResults(100).list() // and useful! List results = session.createFilter( item.getBids(), &quot;select elements (this.bidder.bids)&quot; ).list()
  • 23. Subqueries in HQL Correlated subquery, total items sold by users, if more than 10: Uncorrelated subquery, all bids that are 1 within the maximum: We can use SQL quantifiers, ANY / ALL / SOME / IN: from User user where 10 < ( select count(item) from user.items where item.successfulBid is not null ) from Bid bid where bid.amount + 1 >= ( select max(b.amount) from Bid b ) from Item item where 100 > all ( select b.amount from item.bids b ) from Item item where 100 < any ( select b.amount from item.bids b ) from Item item where 100 = some ( select b.amount from item.bids b ) from Item item where 100 in ( select b.amount from item.bids b )
  • 24. Native SQL queries Direct native SQL queries use Hibernate shortcuts: We can return Object[] s (tuples): We can externalize SQL queries to the mapping file: List results = session.createSQLQuery(&quot;select {uzer.*} from user uzer&quot;, &quot; uzer &quot;, User.class ).list(); List tuples = session.createSQLQuery( &quot;select {u.*}, {b.*} from user u inner join bid b where u.id = b.bidder_id&quot;, new String[] { &quot;u&quot;, &quot;b&quot; }, new Class[] {User.class, Bid.class} ).list(); <sql-query name=&quot;findUsersAndBids&quot;><![CDATA[ select {u.*}, {b.*} from user u inner join bid b where u.id = b.bidder_id ]]> <return alias=&quot;u&quot; class=&quot;User&quot;/> <return alias=&quot;b&quot; class=&quot;Bid&quot;/> </sql-query>