Как заказать результат спящего режима на основе определенного порядка
Мне нужно отправить запрос для извлечения значений, имеющих определенную группу символов, как показано ниже:
Позволяет сказать, что меня интересует "XX" , поэтому он должен искать любое поле, значение которого начинается с "XX" или имеет "XX" (пробел XX). Например, XXCDEF
, PD XXRF
и CMKJIEK XX
являются действительными результатами.
У меня есть следующий запрос:
возвращает правильные результаты, но мне нужно отсортировать их.
таким образом, чтобы он сначала возвращал те, у которых XX
в начале, а затем другие результаты. Как показано ниже:
XXABCD
XXPLER
XXRFKF
AB XXAB
CD XXCD
ZZ XXOI
POLO XX
код
Criteria criteria = session.createCriteria(Name.class, "name")
.add(Restrictions.disjunction()
.add(Restrictions.ilike("name.fname", fname + "%"))
.add(Restrictions.ilike("name.fname", "%" + " " + fname + "%"))
)
.setProjection(Projections.property("name.fname").as("fname"));
List<String> names = (List<String>) criteria.list();
Ответы
Ответ 1
С JPQL (HQL):
select fname from Name
where upper(fname) like :fnameStart or upper(fname) like :fnameMiddle
order by (case when upper(fname) like :fnameStart then 1 else 2 end), fname
query.setParameter("fnameStart", "XX%");
query.setParameter("fnameMiddle", "% XX%");
С критериями
С Criteria
это намного сложнее. Во-первых, вам нужно прибегнуть к родному SQL в предложении order
. Во-вторых, вы должны привязать переменную.
public class FirstNameOrder extends Order {
public FirstNameOrder() {
super("", true);
}
@Override
public String toSqlString(Criteria criteria, CriteriaQuery criteriaQuery) throws HibernateException {
return "case when upper(FIRST_NAME) like ? then 1 else 2 end";
}
}
Синтаксис выражения case и имя функции upper
должны быть изменены в соответствии с вашей базой данных (и имя столбца, если оно отличается, конечно).
Это легко добавить к Criteria
, но API не связывает параметр.
Я попытался обмануть Hibernate, передав неиспользуемую переменную в пользовательское ограничение sql, чтобы оно эффективно использовалось для переменной в предложении order by
:
Criteria criteria = session.createCriteria(Name.class, "name")
.add(Restrictions.disjunction()
.add(Restrictions.ilike("name.fname", fname + "%"))
.add(Restrictions.ilike("name.fname", "%" + " " + fname + "%")))
.setProjection(Projections.property("name.fname").as("fname"))
.add(Restrictions.sqlRestriction("1 = 1", fname + "%", StringType.INSTANCE))
.addOrder(new FirstNameOrder())
.addOrder(Order.asc("fname"));
и он отлично работает.
Очевидно, что это решение не рекомендуется, и я предлагаю использовать JPQL для этого запроса.
Ответ 2
Hibernate поддерживает порядок: http://docs.jboss.org/hibernate/orm/4.2/devguide/en-US/html/ch11.html#ql-ordering
Из-за особых критериев, я думаю, вы должны настраивать заказ в спящем режиме. Эта ссылка может помочь:
http://blog.tremend.ro/2008/06/10/how-to-order-by-a-custom-sql-formulaexpression-when-using-hibernate-criteria-api/
Ответ 3
Запустите два выбора, один отфильтрован для всех строк, начинающихся с "XX", второй отфильтрован для остальных.
Ответ 4
Вы можете использовать Predicates в критериях... что-то вроде этого:
public List<Name> findByParameter(String key, String value, String orderKey)
CriteriaBuilder builder = this.entityManager.getCriteriaBuilder();
CriteriaQuery<Name> criteria = builder.createQuery(this.getClazz());
Root<Name> root = criteria.from(Name.getClass());
criteria.select(root);
List<Predicate> predicates = new ArrayList<Predicate>();
predicates.add(builder.equal(root.get(key), value));
criteria.where(predicates.toArray(new Predicate[predicates.size()]));
if (orderKey!=null && !orderKey.isEmpty()) {
criteria.orderBy(builder.asc(root.get(orderKey)));
}
result = this.entityManager.createQuery(criteria).getResultList();
return result;
}
Ответ 5
Глупо, но это может сработать для вашего дела.
Поскольку вы получили правильный результат, вы можете просто восстановить свои результаты следующим образом:
Обратите внимание. Collections.sort следуют естественному упорядочению своих элементов.
Ответ 6
Если вы не хотите сортировать результат в памяти, вы можете изменить свои критерии, я покажу вам SQL
select * from table where fname like 'XX%' order by fname
union all
select * from table where fname like '% XX%' order by fname
union all
select * from table where fname like '% XX' order by fname
результат будет вашим заказом и алфавитным, а затем применить ваш фильтр.