Module 07 - Hibernate HQL
Module 07 - Hibernate HQL
Language
CS544: Enterprise Architecture
© 2014 Time2Master 1
Retrieving Entities
So far we’ve discussed how to:
Use load() or get() to find an entity by its ID
Access related entities from loaded entities
© 2014 Time2Master 2
Hibernate Query Language
HQLs syntax is relatively similar to SQL, but is
object oriented instead of relational
HQL understands objects and attributes
HQL understands associations between objects
HQL understands inheritance and polymorphism
© 2014 Time2Master 3
Hibernate Query Language:
© 2014 Time2Master 4
The HQL Query Object
Basics of using HQL Queries:
Create a HQL Query: session.createQuery()
Query query = session.createQuery("from Person");
© 2014 Time2Master 5
Named Queries
Named HQL queries can be stored inside mapping data
Can then be retrieved by name for execution
Separates HQL query strings from Java code
Can also be used to organize queries in one location
XML mapping:
<hibernate-mapping package="entities">
<class name="Person">
...
Name needs to be Globally Unique
</class>
<query name="Person.Everybody"><![CDATA[ Use CDATA tags around the query
from Person to make sure < and > comparison
]]></query> operators do not conflict with XML
</hibernate-mapping>
Annotation mapping:
@Entity
@NamedQueries({
Optional @NamedQueries can be used to specify multiple @NamedQuery
@NamedQuery(name="Person.Everybody", query="from Person")
})
public class Person { Globally Unique name
@Id
@GeneratedValue
private int id;
...
© 2014 Time2Master 6
Using Named Queries
Retrieve a named query by its name
Then use it like any other query
session = sessionFactory.openSession(); Query defined
tx = session.beginTransaction();
in metadata
Query query = session.getNamedQuery("Person.Everybody");
List<Person> people = query.list(); Executed like a normal query
for (Person p : people) {
System.out.println(p.getFirstname() + " " + p.getLastname());
}
tx.commit();
© 2014 Time2Master 7
Hibernate Query Language:
© 2014 Time2Master 8
From Clause
The simplest HQL query only contains a ‘from’
clause – the select clause is optional*
List<Person> people = session.createQuery("from Person").list();
© 2014 Time2Master 9
Polymorphic Queries
HQL has very solid polymorphism support
You can query for mapped inheritance hierarchies
Will return all accounts regardless of sub-type
List<Account> accounts = session.createQuery("from Account").list();
© 2014 Time2Master 10
Aliases
You can alias class names for ease of reference
Just like SQL allows you to alias tables names
List<Person> people = session.createQuery("from Person as p").list();
© 2014 Time2Master 11
Pagination
HQL has build in pagination support to select
part of a large result set
Crucial feature when users need to work with
large result sets (like a ‘from Person’ query)
Query query = session.createQuery("from Person");
© 2014 Time2Master 12
Order By
The ‘order by’ clause sorts the list in a
particular order Order people by lastname
Query query = session.createQuery("from Person p order by p.lastname");
List<Person> people = query.list();
for (Person p : people) {
System.out.println(p.getFirstname() + " " + p.getLastname());
}
© 2014 Time2Master 13
Hibernate Query Language:
© 2014 Time2Master 14
The Where Clause
The where clause lets you add constraints to
the result set, refining the list Select all person objects
whose first name is John
Query query = session.createQuery("from Person where firstname = 'John'");
List<Person> people = query.list();
for (Person p : people) {
System.out.println(p.getFirstname() + " " + p.getLastname());
}
© 2014 Time2Master 15
HQL Expressions
Type Operators
Literals ‘string’, 128, 4.5E+3, ‘yyyy-mm-dd hh:mm:ss’
Arithmetic +, -, *, /
Comparison =, <>, >=, <=, !=, like
Logical and, or, not
Grouping (, )
Concatenation ||
Values in, not in, between, is null, is not null, is empty, is not empty
Case case … when … then ... else … end, case when … then … else … end
Type Functions
Temporal current_date(), current_time(), current_timestamp(), second(…),
minute(…), hour(…), day(…), month(…), year(…)
String concat(… , …), substring(), trim(), lower(), upper(), length(), str()
Collection Index(), size(), minindex(), maxindex()
© 2014 Time2Master 16
Indexed Collection Expressions
HQL provides the [] expression syntax for
accessing elements of indexed collections
Query query = session.createQuery("from Person p where p.accounts[0].id = 3");
List<Person> people = query.list();
Accounts is mapped as List
© 2014 Time2Master 17
Query Parameters
It is considered very bad practice to use
concatenation to insert values into Queries
Opens the door for HQL (SQL) injection
Makes query messy and less readable
Makes messy code, and breaks
String firstname = "John"; if there is a ‘ inside firstname
Query query = session.createQuery(
"from Person where firstname = '"+firstname+"'"); Don’t try this at home
© 2014 Time2Master 18
Setting Parameters
Hibernate provides two ways for setting
parameters on queries
1. The setParameter(name, param, [type]) method
String firstname = "John";
Query query = session.createQuery("from Person where firstname = :first");
© 2014 Time2Master 19
Positional Parameters
Hibernate also supports positional parameters
Similar to JDBC using ? to indicate a parameter
First parameter Second parameter
Query query = session.createQuery(
"from CheckingAccount where balance < ? and overdraftLimit > ?");
query.setParameter(0, 1000.0);
query.setParameter(1, 100.0); Set parameters, 0 for the
List<Account> accounts = query.list(); first, 1 for the second
© 2014 Time2Master 20
Unique Result
Use query.uniqueResult() if you are certain
that the result will only contain a single object
Throws NonUniqueResultException if the resultset
contains more than one object
Method returns null if the result set is empty
Query query = session.createQuery("from Person");
query.setMaxResults(1); MaxResults = 1,
Person p1 = (Person) query.uniqueResult();
guarantees unique result
Specific Id guarantees
unique result
© 2014 Time2Master 21
Special Attribute: id
Even if you did not call your identity column
id, you can still refer to it in HQL as id*
Query query1 = session.createQuery("from Employee where employeeId = 1");
Employee e1 = (Employee)query1.uniqueResult();
System.out.println(e1.getFirstname() + " " + e1.getLastname());
Both queries
Query query2 = session.createQuery("from Employee where id = 1");
Employee e2 = (Employee)query2.uniqueResult();
produce the
System.out.println(e2.getFirstname() + " " + e2.getLastname()); same result
@Entity
public class Employee {
@Id Id property
@GeneratedValue “employeeId”
private int employeeId;
private String firstname; Hibernate Output:
private String lastname;
@Temporal(TemporalType.DATE) Hibernate: /* from Employee where employeeId = 1 */ ...
private Date birthdate; Jim Grove
Hibernate: /* from Employee where id = 1 */ ...
... Jim Grove
© 2014 Time2Master 22
Special Attribute: class
Hibernate also provides a special attribute
that allows you to check the class of an object
List<Account> accounts = session.createQuery("from Account act "
+ "where act.class <> CheckingAccount "
+ "and act.owner.firstname = 'Frank'").list();
© 2014 Time2Master 23
Hibernate Query Language:
JOINS
© 2014 Time2Master 24
Joins
Hibernate supports implicit and explicit joins
Explicit joins use the join keyword
Has to explicitly state which class to select
Join keyword
Query query = session.createQuery(
Select p not a "select p from Person p join p.address a where a.zip = :zip");
query.setParameter("zip", "90009");
List<Person> people = query.list();
© 2014 Time2Master 26
Outer Joins
Outer joins allow one side to be null
A left outer join allows the joined object to be null
Query query = session.createQuery("from Person p left outer join p.address a ");
List<Object[]> peopleAddr = query.list();
Outer keyword
is optional
Resultset:
John Willis is included
even though his address Frank Brown Chicago, Illinois
reference was null John Willis
Marry Doe Los Angeles, California
© 2014 Time2Master 28
Only Persons
You have to use explicit joins for collections:
Query query = session.createQuery(
"select p from Person p join p.numbers n where n like :number");
query.setParameter("number", "641%");
List<Person> people = query.list();
© 2014 Time2Master 29
Distinct Keyword
The distinct keyword removes duplicates
Person
© 2014 Time2Master 30
Fetch Joins
Another feature of Hibernate joins is the
ability to eagerly fetch collections
This is done by outer joining the collection in the
sql statement
If you do not outer join, people Loads person and also pre-caches
without an account will be omitted all associated accounts
© 2014 Time2Master 31
Join Fetch Considerations
You can not constrain a join fetch-ed collection
E.g. “from Person p join fetch accounts a where a = …”
is an invalid query
When eager fetching, it is possible that duplicate
initial objects occur due to the outer join
Duplicates can be removed by using ‘select distinct’
Do not fetch more than one collection in parallel,
doing so will create a Cartesian product*
You can not use pagination with eager fetching
© 2014 Time2Master 32
Hibernate Query Language:
© 2014 Time2Master 33
Selecting
The select clause specifies which entities and
or properties the query should return
@Entity
public class Book {
A result can contain: @Id
@GeneratedValue
© 2014 Time2Master 34
Selecting Multiple Items
Using select you can also specify more than
one entity and / or property
By default these will be returned as an Object[]
Query query = session.createQuery( Select an entity and two properties
"select person, pet.species, adr.city "
+ "from Pet pet join pet.owner person "
+ "join person.address adr ");
List<Object[]> items = query.list(); Result set is a List<Object[]>
© 2014 Time2Master 36
Aliases and Maps
The select clause also allows you to specify
aliases for selected values
This is only really useful when using Maps
new map(.., …, …)
Query query = session.createQuery(
"select new map(p as person, sum(a.balance) as liquid) "
+ "from Person p join p.accounts a group by p.id "); Returns List<Map<String, Object>>
List<Map<String,Object>> items = query.list();
Person p = null; Double liquid = null; Aliased values become map keys
for (Map<String,Object> item : items) {
p = (Person)item.get("person"); liquid = (Double)item.get("liquid");
© 2014 Time2Master 37
As New Object
Results can even be formatted as new objects,
provided the required constructor exists
Mapped classes can use their simple class name
Unknown classes need Fully Qualified Domain Name
Fully Qualified Domain Name
Query query = session.createQuery( used: new entities.Home(p, a)
"select new entities.Home(p, a) " No annotations or
+ "from Person p " XML configuration,
+ "join p.address a "); class is unknown to
List<Home> homes = query.list(); Returns a package entities; Hibernate
List<Home>
Person p = null; Address a = null; public class Home {
for (Home home : homes) { private Person person;
p = home.getPerson(); private Address address;
a = home.getAddress();
public Home(Person p, Address a) {
System.out.println(p.getFirstname() this.person = p;
+ " " + p.getLastname() this.address = a; Needs to have
+ " has a home in "+ a.getCity()); } the constructor
} used in the query
...
© 2014 Time2Master 38
Aggregates
HQL also provides aggregate functions:
avg(…), sum(…), min(…), max(…)
count(*), count(…), count(distinct …), count(all …)
Sum of all account balances
Query query = session.createQuery(
"select new map(p as person, sum(a.balance) as liquid) "
+ "from Person p join p.accounts a group by p.id ");
© 2014 Time2Master 40
Bulk Operations
HQL also supports bulk updates and deletes
Similar to the DML features of SQL
Bulk Update:
Query query = session.createQuery("update Account set balance = balance - :fee");
query.setParameter("fee", 5.0);
int updated = query.executeUpdate(); Apply a fee to all accounts
Bulk Delete:
Query query = session.createQuery("delete Book where publish_date < :date");
query.setParameter("date", df.parse("01/01/2002"));
int deleted = query.executeUpdate(); Delete all old books
© 2014 Time2Master 41
Active Learning
If a person can have many cars; write an HQL
query that selects everyone that owns a car that
has color = silver.
© 2014 Time2Master 42
Module Summary
In this module we covered the different aspects
of the Hibernate Query Language
Overall HQL is very similar to SQL
The minimal requirement for a query is a from clause
The where clause can be used to refine the result set
You can implicitly or explicitly join other tables
Using the select clause you can define what should be
returned and in which format it should be returned
HQL can also be used for bulk updates and deletes
© 2014 Time2Master 43