#java #hibernate #jpa #entitymanager #hibernate-criteria
#java #гибернация #jpa #entitymanager #hibernate-критерии
Вопрос:
В моем примере я создал критерии гибернации, используя только мой объект сущности «контракт».
@Transactional
public static List<Contract> findAllContractsPerContract(Contract contract) {
EntityManager e = entityManager().getEntityManagerFactory().createEntityManager();
Session session = e.unwrap(Session.class);
Example contractExample = Example.create(contract).excludeProperty("fromDate").excludeProperty("endDate");;
Criteria c = session.createCriteria(Contract.class).add(contractExample);
// here some restriction can be done. (in a dynamic way like equlas/greater/less...)
List<Contract> list = c.list();
return list;
}
Объект contract имеет много параметров. В этом случае все параметры контракта ищутся равными. Итак, если параметры совпадают, я получаю правильные результаты.
Но теперь я хочу добавить некоторые критерии к некоторым параметрам объекта contract. Например, два параметра: «FromDate» и «EndDate«. Можно изменить существующие критерии, такие как >= FromDate и <=EndDate (или между ними). Критерии также должны быть динамическими.
Я знаю, что могу добавить некоторые критерии в конце этой строки:
Criteria c = session.createCriteria(Contract.class).add(contractExample);
Но это всего лишь дополнение к существующему запросу.
Есть ли решение или другой технический способ решения проблемы?
Спасибо за ввод.
Обновление 1
Запрос без операндов:
allRequestParams={"v00Datvon":"09-07-2014","v00Datbis":"09-07-2014","v00Saicode":{"saiCode":"SO02"}}
Запрос с примером операндов
allRequestParams={"v00Datvon":"09-07-2014","operand":"less","v00Datbis":"09-07-2014","operand":"greater","v00Saicode":{"saiCode":"SO02","operand":"equals"}}
В контроллере я получаю строку JSON следующим образом:
@RequestMapping(value = "/", method = RequestMethod.GET, headers = "Accept=text/plain")
public ResponseEntity<String> getVertagFromSearch(@RequestParam String allRequestParams, ModelMap model) throws JsonProcessingException{
//do stuff
}
Обновление 2
Еще одной большой проблемой является subdomainobject контракта. v00Saicode зависит от контракта. Та же проблема с датами. Без синтаксического анализа строки JSON для contract object я теряю преобразование класса Calender. Я действительно понимаю, как я должен реагировать в контроллере. У кого-нибудь есть решение.
Решение
Это мой способ сделать все части динамическим способом.
Запрос получил дополнительную часть для операторов.
Контроллер получил строку, подобную этой:
@RequestMapping(value = "/", method = RequestMethod.GET, headers = "Accept=text/plain")
public ResponseEntity<String> getVertagFromSearch(@RequestParam String allRequestParams,@RequestParam String operators, ModelMap model) throws JsonParseException, JsonMappingException, IOException, IntrospectionException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
HashMap<String, String> operatorsMap = new ObjectMapper().readValue(operators, HashMap.class);
Contract contract = Contract.fromJsonToContract(allRequestParams);
List<Contract> list = Contract.findAllContractsPerContract(contract, operatorsMap);
HttpHeaders headers = new HttpHeaders();
headers.add("Content-Type", "application/json");
return new ResponseEntity<String>(Contract.toJsonArray(list),headers,HttpStatus.OK);
}
DAO и вызов вспомогательного класса
public static List<Contract> findAllContractsPerContract(Contract contract, Map<String, String> operatorMap) throws IntrospectionException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
EntityManager e = entityManager().getEntityManagerFactory().createEntityManager();
Session session = e.unwrap(Session.class);
Criteria criteria = session.createCriteria(Contract.class);
criteria = CriteriaBuilder.buildCriteria(contract, criteria, operatorMap);
List<Contract> list = criteria.list();
return list;
}
Вспомогательный класс построителя критериев и код ответа @Jeff:
public static Criteria buildCriteria(Object object, Criteria criteria, Map<String,String> operatorMap) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException, IntrospectionException{
BeanInfo vertagInfo = Introspector.getBeanInfo(Contract.class);
for(PropertyDescriptor propertyDescriptor : vertagInfo.getPropertyDescriptors()){
String propertyString = propertyDescriptor.getName();
Object value = propertyDescriptor.getReadMethod().invoke(object);
if(propertyString.equals("class")||value==null){
continue;
}
String operator = operatorMap.get(propertyString);
if(operator==null){
operator="EQ";
}
criteria.add(Comparison.valueOf(operator).convert(propertyString, value));
}
return criteria;
}
Комментарии:
1. Любая другая помощь по этой проблеме?
2. Я не понимаю вашей проблемы на уровне контроллера. Какую библиотеку вы используете для разбора JSON в объекты Java? Вам не нужно соглашаться ни на объект контракта, ни на строку данных; вы должны иметь возможность создать новый DTO (ContractCriteria или что-то в этом роде), на который десериализуется JSON, и у него могут быть внутренние элементы календаря.
3. @Jeff Обновленный ответ проснулся для меня.
Ответ №1:
Возьмите значения для from date и end date из вашего Contract
экземпляра, а затем установите для них значение null в этом экземпляре. Example.create(contract)
не будет добавлять ограничение эквалайзера по умолчанию для этих нулевых полей, и затем вы можете следовать коду @Pracede для выполнения ограничений ge и le.
Вероятно, вы могли бы также вызвать excludeProperty() в своем Example
экземпляре для полей даты, которые вы собираетесь добавить вручную. Это, вероятно, более элегантный способ.
Обновить
Если вам это нужно для динамического построения критериев на основе ввода от пользователя, то запрос по примеру, вероятно, не подходит. Создайте перечисление, которое может обрабатывать все типы сравнения, которые вас интересуют, и возвращать соответствующее сравнение критериев для каждого типа:
public enum Comparison {
EQ {
@Override
public Criterion convert(String propertyName, Object propertyValue) {
return Restrictions.eq(propertyName, propertyValue);
}
},
LE {
@Override
public Criterion convert(String propertyName, Object propertyValue) {
return Restrictions.le(propertyName, propertyValue);
}
},
LIKE {
@Override
public Criterion convert(String propertyName, Object propertyValue) {
return Restrictions.like(propertyName, propertyValue);
}
};
public abstract Criterion convert(String propertyName, Object propertyValue);
}
Затем, когда вы обрабатываете свой ввод JSON в контроллере, получите правильный тип перечисления для каждого сравнения и предоставьте ему необходимое ограничение:
Criteria c = session.createCriteria(Contract.class);
for each name, value, comparator in JSON data*
c.add(Comparison.valueOf(comparator).convert(name, value)
* Примечание: я не предлагаю вам перемещать код DAO в контроллер; вместо передачи экземпляра контракта в ваш DAO передайте массив объектов, которые представляют данные из ввода JSON.
Комментарии:
1. С
excludeProperty()
помощью метода это работает для меня. У вас есть решение для динамического способа создания ограничений гибернации. Потому что я сейчас не знаю, какое ограничение поступит на контроллер. (ge / le / eq) Спасибо.2. Как контроллер указывает, что должно произойти что-то иное, чем сравнение equals?
3. Это должно исходить из части пользовательского интерфейса. Должен быть вызов ajax, который отправляет параметр в формате JSON.
4. Обновленный ответ включает динамические ограничения
5. Это действительно хорошее решение. Есть ли у вас какие-либо предложения, как мне нужно отправить запрос json. И использовать строку в контроллере. Может быть, карта с одним ключом и двумя значениями? Смотрите Подробности в обновленном вопросе
Ответ №2:
Вы пробовали это :
if(fromDate!= null amp;amp; endDate=null) {
criteria.add(Expression.ge("date", fromDate));
criteria.add(Expression.le("date", endDate));
}
Вы должны добавить следующие критерии к текущему.
Комментарии:
1. Я уже пробовал это: c.add (Restrictions.ge («FromDate», contract.getFromDate())) но затем я получаю пустой список. Без добавления объекта в критерии это сработало.
2. Проверьте, совпадает ли формат даты базы данных с тем, который указан по критериям.
3. да, это то же самое. Я думаю, мне нужно написать другой метод для динамического создания ограничений. (CriteriaBuilder) Или есть какое-либо другое решение. Если кому-нибудь понадобится больше информации, пожалуйста, дайте мне знать. Спасибо