Reputation: 8116
Lets say I have a Book Entity like this:
@Entity
@Table(uniqueConstraints = {
@UniqueConstraint(columnNames = {"title"})
})
class Book {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
Long id;
String title;
String author;
String description;
}
and a repository like this:
@Repository
public interface BookRepository extends JpaRepository<Book, Long>, JpaSpecificationExecutor<Book> {
List<Book> findByAuthor(String author);
Book findByTitle(String title);
List<Book> findByDescriptionContaining(String description);
static Specification<Book> hasTitle(String title) {
return (book, cq, cb) -> cb.equal(book.get("title"), title);
}
static Specification<Book> hasAuthor(String author) {
return (book, cq, cb) -> cb.equal(book.get("author"), author);
}
static Specification<Book> hasDescription(String description) {
return (book, cq, cb) -> cb.like(book.get("description"), "%" + description + "%");
}
}
I can then do a query like this:
repository.findAll(where(hasAuthor("Robert Ludlum")).and(hasTitle("The Bourne Identity")).and(hasDescription("also a film"))).
If I have this in a method with parameters, an empty or null value might be passed.
e.g. a REST API search endpoint that has optional parameters.
In that case I would only want to query by author repository.findAll(where(hasAuthor("Robert Ludlum")))
since adding the other predicates would return no results.
I want to start with a base query that includes everything, then if a parameter is not null add that predicate.
If the author was empty in the above example we wouldn't have a hasAuthor
to start the Specification.
How can I conditionally combine the predicates in this way?
Upvotes: 1
Views: 802
Reputation: 1816
You can build your Specification
this way.
Specification<Book> spec = Specification.where(null);
if (byAuthor) {
spec = spec.and(hasAuthor("Robert Ludlum"));
}
if (byTitle) {
spec = spec.and(hasTitle("The Bourne Identity"));
}
...
repository.findAll(where(spec));
Upvotes: 1