rma
rma

Reputation: 51

Filter JPA repository by multiple optional parameters

I have a simple REST service that returns user profile entity that has about 20 fields.

I need to implement a functionality to filter the data where last name is required but all other fields (first name, age, city, state, zip, etc. ) are optional.

Is there a way to do it using JpaRepository without creating a lot of if/else statements for every single combination of patamenters?

Upvotes: 4

Views: 9704

Answers (3)

zeko868
zeko868

Reputation: 182

JpaRepository interface also implements QueryByExampleExecutor interface which provides findAll method for getting data using Query by Example (QBE) technique. That method would be really applicable for your scenario and is actually ideal when entity has a lot of fields and you want user to be able to filter entities by some of them.

Let's say the entity is Person and you want to create endpoint for fetching persons whose properties are equal to the ones which are specified. That could be accomplished with the following code:

Entity class:

@Entity
public class Person implements Serializable {
    private Long id;
    private String firstName;
    private String lastName;
    private Integer age;
    private String city;
    private String state;
    private String zipCode;
}

Controller class:

@Controller
public class PersonController {
    private PersonService service;
    private PersonController(PersonService service) {
        this.service = service;
    }

    @GetMapping
    public List<Person> getMatchingPersons(@RequestBody Person personFilter) {
        return service.findMatchingPersons(personFilter);
    }
}

Service class:

@Service
public class PersonService {
    private PersonRepository repository;
    private PersonService(PersonRepository repository) {
        this.repository = repository;
    }

    public List<Person> getMatchingPersons(Person personFilter) {
        return repository.findAll(Example.of(personFilter));
    }
}

Repository class:

@Repository
public class PersonRepository implements JpaRepository<Person, Long> {
}

Upvotes: 3

davidxxx
davidxxx

Reputation: 131496

It is a use case for JPA criteria (available since JPA2).
In indeed as you want to write a dynamic query, above all, you don't want to hard-coded JPQL queries for each combination and you don't want concatenating chunks of JPQL either as this is error-prone and not checked at compile time.

Note that in any case (Criteria or JPQL) you should check for each possible option if the client has specified it to be able to take them into consideration in the query build.

Now, as you implement the JPARepository interface, you have two ways :

  • using List<T> findAll(@Nullable Specification<T> spec); provided by the JpaSpecificationExecutor interface that you can also implement in your custom repository.

  • Enrich the JPARepository with your own interface that defines a method findAll() and that takes as parameter an object containing values for the research.
    Then create a concrete class to implement JPARepository.
    You would have so the ability to inject the EntityManager and to use the Criteria API.

Upvotes: 3

Pankaj Gadge
Pankaj Gadge

Reputation: 2814

  • It's always best to return a DTO representation of an entity in the REST response.
  • In your DTO, you can only map required fields from an entity and ignore other optional parameters.

Check this out http://www.baeldung.com/entity-to-and-from-dto-for-a-java-spring-application

Upvotes: -1

Related Questions