Hibernate Query Language

Hibernate offers its own query language, called HQL, which resembles SQL in many ways but also supports additional features. There are some differences, for example, instead of the table name, you simply use the entity name and Hibernate will figure out the table name. This is because both HQL and JPA Query Language (JPQL) use an object model, and both languages are considered to be object-oriented and support polymorphism and inheritance concepts.

In this section, we'll focus on HQL and also how Hibernate supports native SQL. However, this section is not meant to be a language reference for HQL; this is indeed a powerful language and most likely deserves its own book. For now, it is highly recommended that you read the online documentations for a complete reference.

When composing HQL statements, you should be aware of the following:

  • HQL is case insensitive, except when you are referring to entity classes. It's a convention to use lowercase for all HQL keywords and use uppercase when referring to entity classes.
  • In more complex HQL statements, entities need to be aliased so that they can be referred to later in the statement.
  • HQL doesn't automatically update the properties that are annotated with @UpdateTimestamp. You'll have to include the timestamp update in the HQL statement.
  • Hibernate supports JPQL, but other JPA implementations may not support HQL.
  • HQL offers various types of parameter binding supporting JDBC style, JPQL, and as well as its own, in the form of named and indexed parameters.

Fetch queries

Typically, you wouldn't use HQL to fetch an entity if you know its primary ID. For this reason, HQL is mostly used to fetch a collection of entities that meet a certain search criteria. For example, you can use HQL to search by the first letter of first name:

List<Person> persons = session
        .createQuery("from Person where firstname like 'J%'")
        .list();

Hibernate will convert this to the following SQL, which looks fairly similar:

select id, firstname, lastname from Person where firstname like 'J%'

Delete and update

Similar to fetch, you should only use HQL to perform bulk deletes and updates:

int numRecs = session 
        .createQuery("delete from Person where lastname = 'Johnson'")
        .executeUpdate();

However, as you can see, you need to call the executeUpdate() method for both delete and update statements, which returns the number of records that are affected by the statements. However, keep in mind that this may not return the count of all the entities that are affected.

Join

As mentioned earlier in this chapter, by default, Hibernate uses the lazy fetch type. If you set the parent entity to eagerly fetch the related entities, Hibernate will also fetch them, even if you don't include the related entity in the HQL. However, this will execute an additional SQL for every parent entity that it fetches. To demonstrate this, let's consider the following entity classes:

@Entity
public class Person {
  @Id
  @GeneratedValue
  private long id;
  private String firstname;
  private String lastname;

  @OneToMany(cascade=CascadeType.ALL, mappedBy="person", 
            fetch=FetchType.EAGER)
  @Fetch(FetchMode.JOIN)
  Set<Address> addresses = new HashSet<Address>();
  // getters and setters
}

@Entity
public class Address {
  @Id
  @GeneratedValue
  private long id;

  private String street;
  private String city;

  @ManyToOne
  private Person person;

  // getters and setters
}

Now, let's use HQL to fetch the Person entities:

persons = session
    .createQuery("from Person where lastname = 'Johnson'")
    .list();

This query returns all the matching Person entities, and then for each Person entity, an additional query is executed to get the related addresses (n+1 queries) even if the fetch mode is set to join, as it is in this case.

To eliminate the n+1 problem, we can use Join in HQL to fetch everything in one query. The fetch keyword in the HQL here instructs Hibernate to retrieve and initialize the associated entities (addresses) when the parent entity is fetched:

List<Person> persons = session
.createQuery("from Person p left join fetch p.addresses where p.lastname = 'Johnson'")
.list();

It's worth noting a few things in this HQL. The first is the use of the p alias. This is needed because we are referring to the entity in other places in the HQL. Secondly, we join the Person and the Address table (using left join), so the query result will include all the columns from persons with their corresponding address. This is a cartesian product of both tables, which is then filtered by matching IDs between an address and a personal record. (It's also filtered by the last name in the where clause.)

Another important note is that the addresses property in the Person entity is being referenced directly. This way, Hibernate knows that you wish to make the join between these two tables, based on their primary key relationship. (Notice that in the join clause or the where clause, we are not specifying person.id = address.person_id; Hibernate does this for us because we are referring to addresses property of Person.)

Finally, the use of the fetch keyword tells Hibernate that we also want to fetch the addresses, and not just the Person, which is similar to an eager fetch.

The HQL translates to something that is similar to the following SQL:

    select
        person0_.id,
        addresses1_.id as address_id,
        person0_.firstname,
        person0_.lastname,
        addresses1_.city,
        addresses1_.street,
        addresses1_.person_id
    from
        Person person0_ 
    left outer join
        Address addresses1_ 
            on person0_.id=addresses1_.person_id 
    where
        person0_.lastname='Johnson'
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.116.118.229