Hibernate Criteria API: получить n случайных строк

Я не могу понять, как извлечь n случайных строк из экземпляра критерия:

Criteria criteria = session.createCriteria(Table.class);
criteria.add(Restrictions.eq('fieldVariable', anyValue));
...

Тогда что? Я не могу найти документ с Criteria API

Означает ли это, что я должен использовать вместо HQL?

Thanx!

РЕДАКТИРОВАТЬ: я получаю количество строк по:

int max = criteria.setProjecxtion(Projections.rowCount()).uniqueResult();

Как мне выбрать n случайных строк с индексами от 0 до макс? Еще раз спасибо!

4 ответа

Решение

На самом деле это возможно с критериями и немного настройки. Вот как:

Criteria criteria = session.createCriteria(Table.class);
criteria.add(Restrictions.eq('fieldVariable', anyValue));
criteria.add(Restrictions.sqlRestriction("1=1 order by rand()"));
criteria.setMaxResults(5);
return criteria.list();

любые Restrictions.sqlRestriction будут добавлять ключевые слова 'и'; поэтому, чтобы аннулировать его эффект, мы добавим фиктивное условие и добавим нашу функцию rand().

Прежде всего, имейте в виду, что в SQL нет стандартного способа сделать это, каждый движок базы данных использует собственный проприетарный синтаксис1. С MySQL оператор SQL для получения 5 случайных строк будет:

SELECT column FROM table
ORDER BY RAND()
LIMIT 5

И вы можете написать этот запрос на HQL, потому что предложение order by в HQL передается в базу данных, поэтому вы можете использовать любую функцию.

String query = "SELECT e.attribute FROM MyEntity e ORDER BY RAND()";
Query q = em.createQuery(query);
q.setMaxResults(5);

Однако, в отличие от HQL, API Criteria в настоящее время не поддерживает ORDER BY Native SQL (см. HHH-2381), и в текущем состоянии вы должны будете создать подкласс Order класс для реализации этой функции. Это выполнимо, обратитесь к проблеме Jira, но не доступно из коробки.

Поэтому, если вам действительно нужен этот запрос, я рекомендую использовать HQL. Просто имейте в виду, что он не будет портативным.

1 Другие читатели могут захотеть проверить пост SQL, чтобы выбрать случайную строку из таблицы базы данных, чтобы увидеть, как реализовать это с MySQL, PostgreSQL, Microsoft SQL Server, IBM DB2 и Oracle.

Criteria API не предоставляет возможности для этого. В MySQL, однако, вы можете использовать ORDER BY RAND() LIMIT n для этого где n представляет количество случайных строк, которые вы хотите получить.

SELECT col1, col2, col3 FROM tbl ORDER BY RAND() LIMIT :n

Вам действительно нужно выполнить его как HQL.

Вы не можете эффективно выбирать случайные строки, извините. Hibernate может делать только то, что делает SQL, и случайная выборка строк просто не является частью какой-либо стандартной реализации SQL, которую я знаю - на самом деле, насколько я знаю, это не часть ЛЮБОГО SQL, о которой я знаю (кто-нибудь, пожалуйста, перечислите меня).

А поскольку Hibernate является картографом O/R, а не чудом, он может делать только то, что поддерживает базовая база данных.

Если у вас есть известное поле с возрастающими числами и вы знаете начало и конец, вы можете сгенерировать случайное число на компьютере и запросить эту строку.

Ответ @PSV Bhat сложен, если вы динамически генерируете свои критерии. Вот решение, расширяющее класс Hibernate Order:

import org.hibernate.Criteria;
import org.hibernate.criterion.Order;

private void addOrderByToCriteria(Criteria criteria) {
    criteria.addOrder(Order.asc("foobar"));
    criteria.addOrder(ORDER_RANDOM);
}

private static final OrderRandom ORDER_RANDOM = new OrderRandom();

private static class OrderRandom extends Order {
    public OrderRandom() {
        super("", false);
    }
    @Override
    public String toSqlString(Criteria criteria, CriteriaQuery criteriaQuery) {
        return "RANDOM()"; // or RAND() or whatever this is in your dialect
    }
}
Другие вопросы по тегам