Reputation: 1330
I have the following method:
public List<Parcel> filter(ParcelFilterParameters pfp) {
try (var session = sessionFactory.getCurrentSession()) {
var baseQuery = "from Parcel ";
var filters = new ArrayList<String>();
pfp.getCustomerId().ifPresent(e -> filters.add(" owner.id = :ownerId "));
pfp.getCategoryId().ifPresent(e -> filters.add(" category.id = :categoryId "));
if (!filters.isEmpty()) {
baseQuery = baseQuery + " where " + String.join(" and ", filters);
}
Query<Parcel> query = session.createQuery(baseQuery, Parcel.class);
pfp.getCustomerId().ifPresent(e -> query.setParameter("ownerId", e));
pfp.getCategoryId().ifPresent(e -> query.setParameter("categoryId", e));
return query.list();
}
}
This is the ParcelFilterParameters class:
public class ParcelFilterParameters {
private Optional<Integer> customerId;
private Optional<Integer> categoryId;
// getters and setters...
}
Although weird looking, it does work, but this repeats for a few other entities so I was wondering if I can make it more generic in some way (without using the Criteria API)? Or at least skip the second batch of ifPresent(e -> ...
s?
Upvotes: 1
Views: 278
Reputation: 331
Although you asked for no Criteria API usage consider using org.hibernate.criterion.Example
. It scales well with a growing number of entities. The example introspects every field that is not null and will build your where
-block from that.
First in the ParcelFilterParameters
we should remove the Optioals
from the fields since Example
works fine with null-values. Then we build a Parcel
-object from the
ParcelFilterParameters
and create an Example
from that. The Example
can be added as an Criterion
to the query.
public List<Parcel> filter(ParcelFilterParameters pfp) {
try (var session = sessionFactory.getCurrentSession()) {
// Build example Parcel from ParcelFilterParameters
Parcel parcel = new Parcel();
// initialize customer/owner and category ...
parcel.getOwner().setId(pfp.getCustomerId());
parcel.getCategory().setId(pfp.getCategoryId());
return session.createCriteria(Parcel.class)
.add(Example.create(parcel))
.list();
}
}
Upvotes: 3
Reputation: 7521
To avoid the second batch of ifPresent
you can use map to hold all query parameters:
List<String> filters = new ArrayList<>();
Map<String, Object> params = new HashMap<>();
pfp.getCustomerId().ifPresent(e -> {
filters.add(" owner.id = :ownerId ");
params.put("ownerId", e);
});
pfp.getCategoryId().ifPresent(e -> {
filters.add(" category.id = :categoryId ");
params.put("categoryId", e);
});
and apply them all in single method call:
Query<Parcel> query = session.createQuery(baseQuery, Parcel.class);
query.setProperties(params);
return query.list();
Upvotes: 2