Ограничение Hibernate вызывает ошибку, если список пуст
Если мой список пуст, я получаю следующую ошибку:
You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ')'
Ниже мой метод, связанный с гибернацией:
@Override
public List<SomeThing> findByIds(List<Integer> someIds) {
return sessionFactory.getCurrentSession().createCriteria(SomeClass.class)
.add(Restrictions.in("id", someIds))
.list();
}
Что делать, чтобы предотвратить эту ошибку?
Я знаю, что я мог бы закоротить вызов и вернуть пустой список, например:
if(someIds == null || someIds.size() == 0) {
return new List<SomeThing>();
}
Но есть ли более элегантный способ сделать это?
Ответы
Ответ 1
НЕТ. Если вы выполняете запрос с пустыми параметрами для предложения in
, он будет терпеть неудачу (вы можете проверить это, выполнив простой SQL). Лучше не выполнять запрос, если входной параметр имеет значение null/empty.
Единственное, что я могу посоветовать, - использовать функцию isEmpty()
и != null
в if
и небольшую реструктуризацию как:
@Override
public List<SomeThing> findByIds(List<Integer> someIds) {
List<Something> result = null; //you may initialize with empty list
if(someIds != null || !someIds.isEmpty() {
result = sessionFactory.getCurrentSession().createCriteria(SomeClass.class)
.add(Restrictions.in("id", someIds))
.list();
}
return result;
}
Ответ 2
Я бы сказал, что Hibernate должен решить эту проблему и дать содержательное сообщение.
Я думаю, что его ответственность провайдера/спящего режима - проверить пустой/нулевой список.
Можно представить причину, она пытается построить where where, что-то вроде id in(), где-то в org.hibernate.loader.criteria.CriteriaQueryTranslator или аналогично. Но поскольку здесь Список пуст, он будет метать исключение. Но они уже создали запрос с помощью (и не могут завершиться из-за исключения/пустого списка.
Ответ 3
(Это в основном основано на ответе @Yogendra Singh с твистом, чтобы сделать его более приемлемым для часто встречающейся ситуации с несколькими необязательными аргументами)
Критерии API направлены на то, чтобы вы запрограммировали свой запрос. Такая динамическая функция, как ожидается, будет обрабатываться в вашем коде.
Обычно мы делаем необязательные критерии:
@Override
public List<SomeThing> findBySearchParams(SearchParam searchParam) {
// create criteria with mandatory search criteria
Criteria criteria = sessionFactory.getCurrentSession()
.createCriteria(SomeClass.class);
.add(Restriction("someField", searchParam.getSomeField()));
// add "id" only if "someId" contains value
if(searchParam.getSomeIds() != null && !searchParam.getSomeIds().empty()) {
criteria.add(Restrictions.in("id", searchParam.getSomeIds()));
}
// add "anotherField" only if "anOptionalField" is not null
if(searchParam.getAnOptionalField() != null) {
criteria.add(Restrictions.in("anotherField", searchParam.getAnOptionalField()));
}
return criteria.list();
}
Edit:
Хотя Hibernate еще не обеспечивает более элегантный способ для этого, вы можете написать что-то сами, чтобы оно выглядело более элегантным:
class SmartCriteriaBuilder {
private Criteria criteria;
SmartCriteriaBuilder (Criteria criteria) { this.criteria = criteria;}
SmartCriteriaBuilder in(String field, Collection values) {
if (!empty(values)) {
this.criteria.add(Restrictions.in(field,values));
}
}
// all other kind of restrictions ....
Criteria toCriteria() {
return this.criteria;
}
}
Тогда вы можете сделать что-то более умное:
SmartCriteriaBuilder criteriaBuilder =
new SmartCriteriaBuilder(sessionFactory.getCurrentSession().createCriteria());
criteriaBuilder .in("someField", listPossiblyNullOrEmpty);
return criteriaBuilder .toCriteria().list();