Mazur Paweł :
I have problem with writing a query in JPA repository because I have a method searching for fathers basing on their name, surname etc.
@Query("select * from father where # ???")
List<Father> searchFather(@Param("fatherBirthDate") LocalDate fatherBirthDate,
@Param("fatherFirstName") String fatherFirstName,
@Param("fatherSurName") String fatherSurName)
And I want to make a 'Search Engine' returning fathers but like this:
- When I do not provide any parameters, the repository will return all fathers
- When I provide for example father name, the query returns a list of father with the provided name
To better explain:
|FATHER_NAME|FATHER_SURNAME|FATHER_BIRTH_DATE|
|JON |SNOW |1992-01-01 |
|JON |ALBY |1993-01-01 |
|JACK |ADLEY |1995-01-01 |
|HARRY |COLBY |1996-01-01 |
- When I provide nothing query return all fathers
- When I provide father name "JON", I expect JON SNOW and JON ALBY
- When I provide surname "COLBY", query will return HARRY COLBY
I trying million times, but I cannot write a query that will return all fathers when I do not provide any parameters and reduce list of found fathers when I provide some parameters.
zpavel :
The simplest way to provide a dynamic search with Spring Boot is to use specifications.
Enable search by specification in your repository class :
public interface FatherRepository extends JpaRepository<Father, Long>, JpaSpecificationExecutor<Father> {}
Create specification class :
public class FatherSpecifications {
public static Specification<Father> hasBirthdate(LocalDate birthdate) {
return (father, cq, cb) -> Optional.ofNullable(birthdate).map(b -> cb.equal(father.get("birthdate"), b)).orElse(null);
}
public static Specification<Father> firstnameLike(String firstname) {
return (father, cq, cb) -> Optional.ofNullable(firstname).map(f -> cb.like(father.get("firstname"), "%" + f + "%")).orElse(null);
}
public static Specification<Father> surnameLike(String surname) {
return (father, cq, cb) -> Optional.ofNullable(surname).map(s -> cb.like(father.get("surname"), "%" + s + "%")).orElse(null);
}
}
Then you can search anywhere in code (where FatherRepository is autowired) with :
List<Father> fathers = fatherRepository.findAll(Specification.where(FatherSpecifications.hasBirthdate(birthdate)).and(FatherSpecifications.firstnameLike(firstname)).and(FatherSpecifications.surnameLike(surname)));