So far, the best solution I have found for this problem, was to extend my JpaRepository
and return a custom object using EntityManager
and Criteria API
. It is an easy to implement solution and quite organized. Also, it allows to reuse the custom repository and just use the needed specification.
For example, let's say that we have the following specification.
public class TopComponentHistorySpecifications {
public static Specification<TopComponentHistory> equalDate(LocaldDateTime date) {
return (root, cq, cb) -> {
if (date != null) return cb.equal(root.get("currDate"), date);
else return cb.and();
};
}
public static Specification<TopComponentHistory> groupByCurrDate() {
return (root, cq, cb) -> {
cb.groupBy(root.get("currDate"));
return cb.and();
};
}
}
Now, we would have our custom repository and model like the ones below.
public class MaxPositionByCurrDate {
private LocalDateTime currDate;
private Long max;
// Rest
}
public interface CustomTopComponentHistoryRepository {
List<MaxPositionByCurrDate> findAllMaxPositionByCurrDate(Specification<TopComponentHistory> specifications);
}
@Repository
public class CustomTopComponentHistoryRepositoryImpl implements CustomTopComponentHistoryRepository {
@PersistenceContext
private EntityManager entityManager;
@Override
List<MaxPositionByCurrDate> findAllMaxPositionByCurrDate(Specification<TopComponentHistory> specifications) {
CriteriaBuilder cb = entityManager.getCriteriaBuilder();
CriteriaQuery<MaxPositionByCurrDate> query = cb.createQuery(MaxPositionByCurrDate.class);
Root<TopComponentHistory> root = query.from(TopComponentHistory.class);
query.where(specifications.toPredicate(root, query, cb), TopComponentHistorySpecifications.groupByCurrDate().toPredicate(root, query, cb));
query.select(cb.construct(MaxPositionByCurrDate.class, root.get("currDate"), cb.max(root.get("maxPosition"))));
return entityManager.createQuery(query).getResultList();
}
}
With this, we can easily re-use our specifications and group them however we want. If you were to add more specifications, you could easily add them ass parameters. For example.
List<MaxPositionByCurrDate> result = this.repository.findAllMaxPositionByCurrDate(Specifications.where(
// Add all the specifications you need, as long as the parameters needed are found on the group by clause
));
Important: I am assuming you know how to extend your JpaRepository
if not, you can check it out here.