2
\$\begingroup\$

I'm trying to implement properly search functionality for database table. I tried this approach:

Controller:

 @GetMapping
 public Page<TransactionDTO> find(TransactionFilterDTO filter, Pageable page) {
 return searchRepository
 .findTransactionsByFilter(mapper.toFilter(filter), page)
 .map(mapper::toDTO);
 }

Filer DTO:

public class TransactionFilterDTO {
 private String name;
 private Integer id;
 @DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME)
 private LocalDateTime from;
 @DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME)
 private LocalDateTime to;
 ... // getters and setter
}

Search implementation:

@Repository
public class TransactionSearchRepositoryImpl implements TransactionSearchRepository {
 @Autowired
 private TransactionRepository transactionRepository;
 @Autowired
 private TransactionSpecification specification;
 @Override
 public Page<Transaction> findTransactionsByFilter(TransactionFilter filter, @Nullable Pageable page) {
 List<Transaction> transactions = transactionRepository
 .findAll(specification.getFilter(filter));
 int totalCount = transactions.size();
 if(page != null) {
 transactions = transactions
 .stream()
 .skip(page.getOffset())
 .limit(page.getPageSize())
 .collect(Collectors.toList());
 }
 return new PageImpl<>(transactions, page, totalCount);
 }
}

Repository:

public interface TransactionSearchRepository {
 Page<Transaction> findTransactionsByFilter(TransactionFilter filter, Pageable page);
}

Is there some better way to implement a search functionality? This solution is very ugly in my view.

asked Apr 16, 2019 at 12:09
\$\endgroup\$

1 Answer 1

2
\$\begingroup\$

In JPA you could use JpaSpecificationExecutor<T> in repository, with that you could utilize it's method.

TransactionRepository

public interface TransactionRepository extends JpaRepository<Transaction, Long>,
 JpaSpecificationExecutor<Transaction> {
}

If you look at the source of JpaSpecificationExecutor it has,

Page< T > findAll(@Nullable Specification<T> spec, Pageable pageable);

With that you just pass the specification and Pageable to return what you expected.

Specification

@AllArgsConstructor
class TransactionSpecification implements Specification<Transaction> {
 private TransactionFilter transactionFilter;
 @Override
 public Predicate toPredicate(Root<DataImport> root, CriteriaQuery<?> query, CriteriaBuilder criteriaBuilder) {
 // You could add multiple Predicates based on the transactionFilter
 return criteriaBuilder.equal(root.get("table_name"), "value");
 }
}

Controller

 @Autowired
 private TransactionRepository transactionRepository;
 @GetMapping
 public Page<TransactionDTO> find(TransactionFilterDTO filter, Pageable page) {
 TransactionFilter transactionFilter = mapper.toFilter(filter);
 return transactionRepository.findAll(new TransactionSpecification(transactionFilter), page);
 }

I am pretty late answering but you could give it a try

Sᴀᴍ Onᴇᴌᴀ
29.5k16 gold badges45 silver badges201 bronze badges
answered Jun 6, 2019 at 10:31
\$\endgroup\$

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.