Hibernate FAQ  - Tips and Tricks


Tips and Tricks

Here are some tips and tricks you might find useful while crafting with Hibernate.

How can I count the number of query results without actually returning them?

 

Integer count = (Integer) session.createQuery("select count(*) from ....").uniqueResult();

 

How can I find the size of a collection without initializing it?

 

Integer size = (Integer) s.createFilter( collection, "select count(*)" ).uniqueResult();

 

How can I order by the size of a collection?

Use a left join, together with group by


select user 
from User user
left join user.messages msg
group by user 
order by count(msg)

 

How can I place a condition upon a collection size?

If your database supports subselects:

 

from User user where size(user.messages) >= 1

 

or:

 

from User user where exists elements(user.messages)

 

If not, and in the case of a one-to-many or many-to-many association:

 

select user 
from User user 
join user.messages msg 
group by user 
having count(msg) >= 1

 

Because of the inner join, this form can't be used to return a User with zero messages, so the following form is also useful

 

select user 
from User as user
left join user.messages as msg
group by user 
having count(msg) = 0

 

How can I query for entities with empty collections?

 

from Box box
where box.balls is empty

 

Or, try this:

 

select box
from Box box
   left join box.balls ball
where ball is null

 

How can I sort / order collection elements?

There are three different approaches:

  1. Use a SortedSet or SortedMap, specifying a comparator class in the sort attribute or <set> or <map>. This solution does a sort in memory.
  2. Specify an order-by attribute of <set>, <map> or <bag>, naming a list of table columns to sort by. This solution works only in JDK 1.4+.
  3. Use a filter session.createFilter( collection, "order by ...." ).list()

 

Are collections pageable?

 

Query q = s.createFilter( collection, "" ); // the trivial filter
q.setMaxResults(PAGE_SIZE);
q.setFirstResult(PAGE_SIZE * pageNumber);
List page = q.list();

 

I have a one-to-one association between two classes. Ensuring that associated objects have matching identifiers is bugprone. Is there a better way?

 

<generator class="foreign">
     <param name="property">parent</param>
</generator>

 

I have a many-to-many association between two tables, but the association table has some extra columns (apart from the foreign keys). What kind of mapping should I use?

Use a composite-element to model the association table. For example, given the following association table:

 

create table relationship ( 
    fk_of_foo bigint not null, 
    fk_of_bar bigint not null, 
    multiplicity smallint, 
    created date )

 

you could use this collection mapping (inside the mapping for class Foo):

 

<set name="relationship">
    <key column="fk_of_foo"/>
    <composite-element class="Relationship">
        <property name="multiplicity" type="short" not-null="true"/>
        <property name="created" type="date" not-null="true"/>
        <many-to-one name="bar" class="Bar" not-null="true"/>
    </composite-element>
</set>

 

You may also use an <idbag> with a surrogate key column for the collection table. This would allow you to have nullable columns.

 

An alternative approach is to simply map the association table as a normal entity class with two bidirectional one-to-many associations.

 

In an MVC application, how can we ensure that all proxies and lazy collections will be initialized when the view tries to access them?

One possible approach is to leave the session open (and transaction uncommitted) when forwarding to the view. The session/transaction would be closed/committed after the view is rendered in, for example, a servlet filter (another example would by to use the ModelLifetime.discard()  callback in Maverick). One difficulty with this approach is making sure the session/transaction is closed/rolled back if an exception occurs rendering the view.

 

Another approach is to simply force initialization of all needed objects using Hibernate.initialize(). This is often more straightforward than it sounds.Another approach is to simply force initialization of all needed objects using Hibernate.initialize(). This is often more straightforward than it sounds.

 

How can I bind a dynamic list of values into an in query expression?

 

Query q = s.createQuery("from foo in class Foo where foo.id in (:id_list)");
q.setParameterList("id_list", fooIdList);
List foos = q.list();

 

How can I bind properties of a JavaBean to named query parameters?

 

Query q = s.createQuery("from foo in class Foo where foo.name=:name and foo.size=:size");
q.setProperties(fooBean); // fooBean has getName() and getSize()
List foos = q.list();

 

Can I map an inner class?

You may persist any static inner class. You should specify the class name using the standard form ie. eg. Foo$Bar

 

How can I assign a default value to a property when the database column is null?

Use a UserType.

 

How can I trucate String data?

Use a UserType.

 

How can I trim spaces from String data persisted to a CHAR column?

Use a UserType.

 

How can I convert the type of a property to/from the database column type?

Use a UserType.

 

How can I get access to O/R mapping information such as table and column names at runtime?

This information is available via the Configuration object. For example, entity mappings may be obtained using Configuration.getClassMapping(). It is even possible to manipulate this metamodel at runtime and then build a new SessionFactory.

 

How can I create an association to an entity without fetching that entity from the database (if I know the identifier)?

If the entity is proxyable (lazy="true"), simply use load(). The following code does not result in any SELECT statement:

 

Item itemProxy = (Item) session.load(Item.class, itemId);
Bid bid = new Bid(user, amount, itemProxy);
session.save(bid);

 

How can I retrieve the identifier of an associated object, without fetching the association?

Just do it. The following code does not result in any SELECT statement, even if the item association is lazy.

 

Long itemId = bid.getItem().getId();

 

This works if getItem() returns a proxy and if you mapped the identifier property with regular accessor methods. If you enabled direct field access for the id of an Item, the Item proxy will be initialized if you call getId(). This method is then treated like any other business method of the proxy, initialization is required if it is called.

 

How can I manipulate mappings at runtime?

You can access (and modify) the Hibernate metamodel via the Configuration object, using getClassMapping(), getCollectionMapping(), etc.

 

Note that the SessionFactory is immutable and does not retain any reference to the Configuration instance, so you must re-build it if you wish to activate the modified mappings.

 

How can I avoid n+1 SQL SELECT queries when running a Hibernate query?

Follow the best practices guide! Ensure that all <class> and <collection> mappings specify lazy="true" in Hibernate2 (this is the new default in Hibernate3). Use HQL LEFT JOIN FETCH to specify which associations you need to be retrieved in the initial SQL SELECT.

 

A second way to avoid the n+1 selects problem is to use fetch="subselect" in Hibernate3.

 

If you are still unsure, refer to the Hibernate documentation and Hibernate in Action.

 

I have a collection with second-level cache enabled, and Hibernate retrieves the collection elements one at a time with a SQL query per element!

Enable second-level cache for the associated entity class. Don't cache collections of uncached entity types.

 

How can I insert XML data into Oracle using the xmltype() function?

Specify custom SQL INSERT (and UPDATE) statements using <sql-insert> and <sql-update> in Hibernate3, or using a custom persister in Hibernate 2.1.

 

You will also need to write a UserType to perform binding to/from the PreparedStatement.

 

How can I execute arbitrary SQL using Hibernate?

 

PreparedStatement ps = session.connection().prepareStatement(sqlString);

 

Or, if you wish to retrieve managed entity objects, use session.createSQLQuery().

 

Or, in Hibernate3, override generated SQL using <sql-insert>, <sql-update>, <sql-delete> and <loader> in the mapping document.

 

I want to call an SQL function from HQL, but the HQL parser does not recognize it!

Subclass your Dialect, and call registerFunction() from the constructor.