Reputation: 35
I have a query that needs a dynamic SQL WHERE
clauses based on filters.
It may give me a NullPointerException (NPE) if I'm adding an "AND"
while the previous filter is not existing.
public List<BlocageDeblocageCompte> getMyQuery(FiltersDTO filters) {
JPAQuery<MY_ENTITY> myEntity = getJPAQueryFactory().selectFrom(myEntity).limit(20);
BooleanExpression whereClause = null;
boolean whereClauseAdded = false;
boolean ifNoFilter = Stream.of(myEntity).allMatch(Objects::isNull);
if (ifNoFilter) {
return new ArrayList<>(myEntity.fetchAll().fetch());
}
if (filters.getId() != null) {
whereClause = myEntity.id.eq(filters.getId());
whereClauseAdded = true;
}
if (filters.getName() != null) {
if (whereClauseAdded) {
whereClause = whereClause.and(myEntity.id.eq(filters.getName()));
} else {
whereClause = myEntity.id.eq(filters.getName());
whereClauseAdded = true;
}
}
// remaining code
}
Is there a better way to add the filters, without risking a NPE?
Upvotes: 0
Views: 1818
Reputation: 179
You can implement the Specification
interface in JPA:
Filter
class with static predicate-methods to handle fields in WHERE clause:public class Filter{
public static Specification<BlocageDeblocageCompte> hasName(String name) {
return (root, query, cb) -> {
if (name == null || name.equals("")) {
return cb.isTrue(cb.literal(true)); // always true = no filtering
}
return cb.like(root.get("name"), "%" + name + "%");
};
}
public static Specification<ActiveAlarm> hasId(Integer id) {
return (root, query, cb) -> {
if (id == null) {
return cb.isTrue(cb.literal(true)); // always true = no filtering
}
return cb.equal(root.get("id"), id);
};
}
}
Filter
class in your methods:repository.findAll(where(Filter.hasName(filters.getName()).and(Filter.hasId(filters.getId()));
For more details, see:
Upvotes: 1
Reputation: 35
I found out a simple solution, when we do WHERE on all of them it transform automatically the second where to AND. thank u guys.
JPAQuery<MyEntity> myEntityJPAQUERY=
getJPAQueryFactory()
.selectFrom(QmyEntity);
if (filtresDTO.getId() != null) {
myEntityJPAQUERY=myEntityJPAQUERY.where(QmyEntity.id.eq(ffiltresDTO.getId()));
if (filtresDTO.getName() != null) {
myEntityJPAQUERY=myEntityJPAQUERY.where(QmyEntity.name.eq(ffiltresDTO.getName()))
}
Upvotes: -1
Reputation: 9377
To construct complex boolean queries like this you can use com.querydsl.core.BooleanBuilder
:
public List<MyEntity> getMyQuery(FiltersDTO filters) {
MyEntity myEntity = QModel.myEntity;
// build an optional WHERE clause with predicates using AND conjunctions
BooleanBuilder builder = new BooleanBuilder();
if (filters.getId() != null) {
builder.and(myEntity.id.eq(filters.getId()));
}
if (filters.getName() != null) {
builder.and(myEntity.id.eq(filters.getName()));
}
// construct the query
return getJPAQueryFactory().selectFrom(myEntity)
.limit(20)
.where(builder) // myEntity.id eq id1 AND myEntity.name eq name1
.fetch();
}
Similar questions:
References:
Upvotes: 1