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
}
}