使用JPA条件API进行日期比较

ale*_*der 3 jpa date criteria-api

我有一个带有两个日期的范围日期选择器:startend,两个日期都可以为空。我想过滤一张表,其中实体有一个确切的日期:date

因此,这里有一些例子。我想比赛。想象要匹配的日期是当前日期(17/07/2016)。

  • null-17/07/2016->比赛
  • 17/07/2016-空->匹配
  • 2016/07/17-2016/07/17->比赛
  • null-null->全部匹配

在我看来,这些都是极端情况,也是我之所以如此努力的原因。

实际上我的代码如下:

CriteriaBuilder cb = getEm().getCriteriaBuilder();
CriteriaQuery<Transaction> cq = cb.createQuery(Transaction.class);
Root<Transaction> root = cq.from(Transaction.class);

List<Predicate> predicates = new ArrayList<>();

Predicate startPredicate = cb.greaterThanOrEqualTo(root.get(Transaction_.date), start);
Predicate endPredicate = cb.greaterThanOrEqualTo(root.get(Transaction_.date), end);

predicates.add(startPredicate);
predicates.add(endPredicate);
cq.select(root).where(predicates.toArray(new Predicate[] {}));

TypedQuery<Transaction> query = getEm().createQuery(cq);
query.setFirstResult(firstRow);
query.setMaxResults(maxRow);
List<Transaction> resultList = query.getResultList();
Run Code Online (Sandbox Code Playgroud)

我想得到这样的查询:

CriteriaBuilder cb = getEm().getCriteriaBuilder();
CriteriaQuery<Transaction> cq = cb.createQuery(Transaction.class);
Root<Transaction> root = cq.from(Transaction.class);

List<Predicate> predicates = new ArrayList<>();

Predicate startPredicate = cb.greaterThanOrEqualTo(root.get(Transaction_.date), start);
Predicate endPredicate = cb.greaterThanOrEqualTo(root.get(Transaction_.date), end);

predicates.add(startPredicate);
predicates.add(endPredicate);
cq.select(root).where(predicates.toArray(new Predicate[] {}));

TypedQuery<Transaction> query = getEm().createQuery(cq);
query.setFirstResult(firstRow);
query.setMaxResults(maxRow);
List<Transaction> resultList = query.getResultList();
Run Code Online (Sandbox Code Playgroud)

请注意:静态日期是模拟开始日期和结束日期。并且date是表格列。

我知道我的代码是错误的。它仅匹配范围,而不考虑空值。另外,如果开始和结束是同一天,我将得到零结果。

你有什么主意吗 如何编辑代码以匹配所有提到的模式?

Tin*_*iny 7

我有一个现有的数据库表,该表具有一个名为MySQL 和MySQL的discount两列类型。因此,请根据表名和该表中的相应列调整查询。TIMESTAMPdiscount_start_datediscount_end_date

基于问题中给出的SQL语句的完整条件查询可以按以下方式构造(我希望代码是不言自明的)。

CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();
CriteriaQuery<Discount> criteriaQuery = criteriaBuilder.createQuery(Discount.class);
Root<Discount> root = criteriaQuery.from(entityManager.getMetamodel().entity(Discount.class));

SimpleDateFormat dateFormat = new SimpleDateFormat("dd-MM-yyyy");
java.util.Date startDate = dateFormat.parse("24-02-2016");
java.util.Date endDate = dateFormat.parse("24-03-2016");

ParameterExpression<java.util.Date> parameter = criteriaBuilder.parameter(java.util.Date.class);

Predicate startDatePredicate = criteriaBuilder.greaterThanOrEqualTo(root.get(Discount_.discountStartDate).as(java.sql.Date.class), parameter);
Predicate endDatePredicate = criteriaBuilder.lessThanOrEqualTo(root.get(Discount_.discountEndDate).as(java.sql.Date.class), parameter);

Predicate startDateOrPredicate = criteriaBuilder.or(startDatePredicate, root.get(Discount_.discountStartDate).isNull());
Predicate endDateOrPredicate = criteriaBuilder.or(endDatePredicate, root.get(Discount_.discountEndDate).isNull());

Predicate and = criteriaBuilder.and(startDateOrPredicate, endDateOrPredicate);
criteriaQuery.where(and);

List<Discount> list = entityManager.createQuery(criteriaQuery)
        .setParameter(parameter, startDate, TemporalType.DATE)
        .setParameter(parameter, endDate, TemporalType.DATE)
        .getResultList();
Run Code Online (Sandbox Code Playgroud)

它会产生您感兴趣的以下SQL查询(两个字段都包含在内,如您所述)。

select
    discount0_.discount_id as discount1_15_,
    discount0_.discount_code as discount2_15_,
    discount0_.discount_end_date as discount3_15_,
    discount0_.discount_percent as discount4_15_,
    discount0_.discount_start_date as discount5_15_ 
from
    project.discount discount0_ 
where
    (
        cast(discount0_.discount_start_date as date)>=? 
        or discount0_.discount_start_date is null
    ) 
    and (
        cast(discount0_.discount_end_date as date)<=? 
        or discount0_.discount_end_date is null
    )
Run Code Online (Sandbox Code Playgroud)

经过Hibernate 4.3.6最终版本测试,但普通的ORM框架应产生相同的查询而无需任何修改。


在此方法中setParameter(parameter, startDate, TemporalType.DATE)TemporalType.DATE仅当您具有类型的列DATETIMETIMESTAMP数据库中并且要比较日期而忽略此类列的时间部分时,才需要最后一个参数ie 。如果您的列没有像DATE(MySQL)这样的时间部分,则可以简单地排除该参数。

你可以,如果需要的话,还可以使用其他日期(时间)处理API,如java.timeJodaTime更换Date沿SimpleDateFormat