使用 JPA 标准进行日期比较 API
Date comparison using the JPA criteria API
我得到了一个包含两个日期的范围日期选择器:start
和 end
,两者都可以为空。我想过滤一个 table,其中实体有一个确切的日期:date
.
所以,这里有一些例子。我想匹配。成像日期要匹配的是当前日期(17/07/2016)。
- null - 17/07/2016 -> 匹配
- 17/07/2016 - 空 -> 匹配
- 17/07/2016 - 17/07/2016 -> 比赛
- 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();
我想得到这样的查询:
SELECT * FROM transaction
WHERE ((cast(date AS DATE) >= '2016-07-16' OR cast(date AS DATE) IS NULL))
AND ((cast(date AS DATE) <= '2016-07-17' OR cast(date AS DATE) IS NULL))
请注意:静态日期是模拟开始和结束日期。 date
是 table 列。
我知道我的代码是错误的。它只匹配范围,不考虑空值。此外,如果开始和结束是同一天,我将得到零结果。
你有什么想法吗?如何编辑我的代码以匹配所有提到的模式?
我有一个名为 discount
的现有数据库 table,在 MySQL 中有两列名为 discount_start_date
和 discount_end_date
的类型 TIMESTAMP
数据库。因此,请根据 table 的名称和 table.
中的相应列调整您的查询
基于问题中给出的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();
它会生成您感兴趣的以下 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
)
已在 Hibernate 4.3.6 final 上进行测试,但一般的 ORM 框架应该无需任何修改即可生成相同的查询。
在这个方法 setParameter(parameter, startDate, TemporalType.DATE)
中,如果你的数据库中有一个 DATETIME
或 TIMESTAMP
类型的列并且你想要比较忽略此类列的时间部分的日期。如果您的列没有像 DATE
(MySQL).
这样的时间部分,您可以简单地排除该参数
如有必要,您还可以使用其他日期(时间)处理 API,例如 java.time
或 JodaTime
替换 Date
以及 SimpleDateFormat
我得到了一个包含两个日期的范围日期选择器:start
和 end
,两者都可以为空。我想过滤一个 table,其中实体有一个确切的日期:date
.
所以,这里有一些例子。我想匹配。成像日期要匹配的是当前日期(17/07/2016)。
- null - 17/07/2016 -> 匹配
- 17/07/2016 - 空 -> 匹配
- 17/07/2016 - 17/07/2016 -> 比赛
- 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();
我想得到这样的查询:
SELECT * FROM transaction
WHERE ((cast(date AS DATE) >= '2016-07-16' OR cast(date AS DATE) IS NULL))
AND ((cast(date AS DATE) <= '2016-07-17' OR cast(date AS DATE) IS NULL))
请注意:静态日期是模拟开始和结束日期。 date
是 table 列。
我知道我的代码是错误的。它只匹配范围,不考虑空值。此外,如果开始和结束是同一天,我将得到零结果。
你有什么想法吗?如何编辑我的代码以匹配所有提到的模式?
我有一个名为 discount
的现有数据库 table,在 MySQL 中有两列名为 discount_start_date
和 discount_end_date
的类型 TIMESTAMP
数据库。因此,请根据 table 的名称和 table.
基于问题中给出的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();
它会生成您感兴趣的以下 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
)
已在 Hibernate 4.3.6 final 上进行测试,但一般的 ORM 框架应该无需任何修改即可生成相同的查询。
在这个方法 setParameter(parameter, startDate, TemporalType.DATE)
中,如果你的数据库中有一个 DATETIME
或 TIMESTAMP
类型的列并且你想要比较忽略此类列的时间部分的日期。如果您的列没有像 DATE
(MySQL).
如有必要,您还可以使用其他日期(时间)处理 API,例如 java.time
或 JodaTime
替换 Date
以及 SimpleDateFormat