Im creating a hibernate criteria that will check if a contract is/has been valid during a year. The contract has a start and end-date as a standard date-field.
So being used to SQL-SERVER, i would think something in the lines of this SQL:
SELECT * FROM CONTRACT WHERE YEAR(startDate) <= ? AND YEAR(endDate) >= ?
The questionmark is the given year as an integer.
So how to transform this to a hibernate criteria?
int year = 2011; //Just a testyear for example purposes.
DetachedCriteria criteria = DetachedCriteria.forClass(Contract.class)
.add(Restrictions.le("startDate", year))
.add(Restrictions.ge("endDate", year));
As you can see, i am missing the bit where i convert the date's to a year so it can be compared. Naturally my code does not run as it is.
Any suggestion on how to get the desired results?
It seem like the API does not directly support what you wanted, but there is workaround that you might consider.
Solution 1:
DetachedCriteria criteria = DetachedCriteria.forClass(Contract.class)
.add(Restrictions.le("startDate", toEndOfYear(year))
.add(Restrictions.ge("endDate", toStartOfYear(year)));
public Date toStartOfYear(int year) {
Calendar calendar = Calendar.getInstance();
calendar.set(Calendar.YEAR, year);
calendar.set(Calendar.DAY_OF_YEAR, 0);
calendar.set(Calendar.HOUR_OF_DAY, 0);
calendar.set(Calendar.MINUTE, 0);
calendar.set(Calendar.SECOND, 0);
return calendar.getTime();
}
public Date toEndOfYear(int year) {
Calendar calendar = Calendar.getInstance();
calendar.set(Calendar.YEAR, year);
calendar.set(Calendar.DAY_OF_YEAR, 0);
calendar.set(Calendar.HOUR_OF_DAY, 0);
calendar.set(Calendar.MINUTE, 0);
calendar.set(Calendar.SECOND,-1);
return calendar.getTime();
}
Example output of the two methods:
System.out.println(toStartOfYear(2013));
System.out.println(toEndOfYear(2013));
Mon Dec 31 00:00:00 MYT 2012
Sun Dec 30 23:59:59 MYT 2012
Solution 2:
DetachedCriteria criteria = DetachedCriteria.forClass(Contract.class)
.add(Restrictions.sqlRestriction("YEAR(startDate) >= ? ", year,Hibernate.INTEGER))
.add(Restrictions.sqlRestriction("YEAR(endDate) <= ? ", year,Hibernate.INTEGER));
If you use JPA criteriaBuilder, you can use the criteriaBuilder.function
method. E.g.
contractRepository.findAll(new Specification<Contract>() {
@Override
public Predicate toPredicate(Root<Contract> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
return cb.ge(cb.function("year", Integer.class, root.get(Contract_.endDate)), year);
}
});
(I use Spring Data Specifications in this example to query the database. contractRepository
is thus of type JpaSpecificationExecutor
)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With