Lantana

I recently found myself in the situation where I needed Hibernate to query a single, random entry from a table of Picture entities.

There is a simple way. Some DBMS allow to shuffle the result set by bringing the rows into a random order. For instance, in MySQL it is possible to use a query like this:

SELECT id FROM picture ORDER BY rand() LIMIT 1;

Since Hibernate delegates unknown function calls to the underlying DBMS, rand() could be used in a HQL query as well:

q.createQuery("FROM picture ORDER BY rand()").setMaxResults(1);

However this query would require MySQL, so we would sacrifice the benefit of Hibernate acting as an abstraction layer to the underlying database. HQL on the other hand does not offer a similar function.

A solution is to use the pagination technique. First we count the number of entries, and then select a random entry using setFirstResult(). With Hibernate Criteria, it would look something like this:

Criterion restriction = yourRestrictions;
Object result = null;  // will later contain a random entity
Criteria crit = session.createCriteria(Picture.class);
crit.add(restriction);
crit.setProjection(Projections.rowCount());
int count = ((Number) crit.uniqueResult()).intValue();
if (0 != count) {
  int index = new Random().nextInt(count);
  crit = session.createCriteria(Picture.class);
  crit.add(restriction);
  result = crit.setFirstResult(index).setMaxResults(1).uniqueResult();
}

restriction contains further restrictions to the result set (like only pictures that have been published). At the end, result contains a random single entry from the Picture entity, or null if the result set was empty.