Работа с данными весны jpa и спецификациями, у меня есть требование реализовать функцию фильтра/поиска весной mvc. Бэкэнд получает объект (ReportTemplateBean), который в основном является компонентом с некоторыми полями, которые представляют фильтры в интерфейсе.Динамические запросы в Spring Data JPA. Рефакторинг
public class ReportTemplateBean implements Serializable {
private static final long serialVersionUID = -3915391620260021813L;
private Long id;
private String property;
private String city;
private String state;
private String zipCode;
private String propertyStatus;
private String realEstateRep;
//more code
У нас есть контроллер
@RequestMapping(value = "/search", method = RequestMethod.GET)
@ResponseBody
public ReportBean search(@AuthenticationPrincipal ActiveUser activeUser,
@ModelAttribute("templateForm") ReportTemplateBean template,
Pageable pageable) throws GenericException {
LOGGER.info("Pulling report requested");
ReportBean report = reportService.searchProperties(template,
pageable.getPageNumber(), pageable.getPageSize());
return report;
}
Службы
@Override
@Transactional(readOnly = true, timeout = 20)
public ReportBean searchProperties(ReportTemplateBean template,
Integer pageNumber, Integer pageSize) throws GenericException,
TransactionTimedOutException {
LOGGER.info("searchProperties({})", template);
try {
// pageNumber = (pageNumber == null ? 0 : pageNumber);
// pageSize = (pageSize == null ? 10 : pageSize);
ReportTemplate t = reportTemplateMapper.beanToEntity(template);
List<PropertyBean> beans = new ArrayList<PropertyBean>();
PropertySpecification spec = new PropertySpecification(t);
Page<Property> properties = propertyRepository.findAll(spec,
new PageRequest(pageNumber, pageSize, Sort.Direction.ASC,
"name"));
И тогда он строит запрос динамически, но используя длинную цепочку IF, что мне не нравится это. Это спецификация.
@SuppressWarnings("unchecked")
@Override
public Predicate toPredicate(Root<Property> root, CriteriaQuery<?> query,
CriteriaBuilder cb) {
Path<String> propertyName = root.get(Property_.name);
Path<String> city = root.get(Property_.city);
Path<String> state = root.get(Property_.state);
Path<String> zipCode = root.get(Property_.zipCode);
final List<Predicate> orPredicates = new ArrayList<Predicate>();
final List<Predicate> andPredicates = new ArrayList<Predicate>();
if (template.getProperty() != null
&& template.getProperty().length() > 0) {
andPredicates.add(cb.equal(propertyName, template.getProperty()));
}
if (template.getCity() != null && template.getCity().length() > 0) {
andPredicates.add(cb.equal(city, template.getCity()));
}
if (template.getState() != null && template.getState().length() > 0) {
andPredicates.add(cb.equal(state, template.getState()));
}
if (template.getZipCode() != null && template.getZipCode().length() > 0) {
andPredicates.add(cb.equal(zipCode, template.getZipCode()));
}
if (template.getRealEstateRep() != null) {
Join<Property, User> pu = null;
if (query.getResultType().getName().equals("java.lang.Long")) {
pu = (Join<Property, User>) root.fetch(Property_.createdBy);
} else {
pu = root.join(Property_.createdBy);
}
Path<Long> userId = pu.get(User_.id);
andPredicates.add(cb.equal(userId, template.getRealEstateRep()));
}
if (template.getProjectType() != null
&& template.getProjectType().length() > 0) {
Join<Property, Project> pp = null;
if (query.getResultType().getName().equals("java.lang.Long")) {
pp = root.join(Property_.projects);
} else {
pp = (Join<Property, Project>) root.fetch(Property_.projects);
}
Path<String> projectType = pp.get(Project_.projectName);
andPredicates.add(cb.equal(projectType, template.getProjectType()));
}
//more IF's
return query.getRestriction();
}
Как вы можете заметить Спецификацию кажется уродливым и, кроме того, что SONAR жалуется цикломатической Сложностью этого метода (что хорошо).
Вопрос в том, как я могу реорганизовать спецификацию (IF), чтобы быть более OO-кодом ?. Спасибо заранее. UPDATE - Я хотел бы использовать/реализовать что-то вроде новой функции в Spring Data JPA (Query by Example) Кажется, что если вы передаете Бин ExampleMatcher класс будет игнорировать нулевое значение в полях боба, который почти что Я ищу. Игнорировать нулевые и пустые значения.
Вы хотите решение только с использованием Спецификации? У меня была аналогичная проблема, но я решил написать запрос с помощью аннотации @Query с дополнительными параметрами в моем репозитории. – amicoderozer
Было бы неплохо использовать спецификацию, но не обязательно, могу ли я взглянуть на ваше решение? – TheProgrammer