使用CriteriaBuilder将Date转Long时遇类型转换异常求助
解决JPA CriteriaBuilder日期转数字并计算差值的类型转换异常
嘿,我来帮你搞定这个问题!你遇到的类型转换异常,核心原因是不能直接把Date类型的Expression通过as(Long.class)强制转成数值类型——JPA没办法自动把数据库的DATE类型映射到Long,得先借助数据库原生的日期处理函数,把日期转成yyyymmdd这种纯数字格式的字符串,再转成Long类型,最后才能计算差值。
下面分步骤给你具体的解决方案,适配不同数据库:
核心思路
用CriteriaBuilder.function()调用数据库的日期格式化函数,把日期转为yyyymmdd格式的字符串,再将字符串转为Long,最后用builder.diff()计算两个数值的差。
针对不同数据库的代码实现
1. MySQL数据库
用DATE_FORMAT函数格式化日期:
CriteriaBuilder builder = sf.getCurrentSession().getCriteriaBuilder(); CriteriaQuery<Tuple> criteria = builder.createTupleQuery(); Root<PreVenda> root = criteria.from(PreVenda.class); // 把dataPrevVenda转成yyyymmdd格式的字符串,再转Long Expression<String> dataPrevVendaStr = builder.function( "DATE_FORMAT", String.class, root.get(PreVenda_.dataPrevVenda), builder.literal("%Y%m%d") // 格式化规则:4位年+2位月+2位日 ); Expression<Long> dataPrevVendaNum = dataPrevVendaStr.as(Long.class); // 同样处理dataRealVenda Expression<String> dataRealVendaStr = builder.function( "DATE_FORMAT", String.class, root.get(PreVenda_.dataRealVenda), builder.literal("%Y%m%d") ); Expression<Long> dataRealVendaNum = dataRealVendaStr.as(Long.class); // 计算两个数值的差值 criteria.select(builder.tuple(builder.diff(dataRealVendaNum, dataPrevVendaNum)));
2. Oracle数据库
用TO_CHAR函数格式化日期:
CriteriaBuilder builder = sf.getCurrentSession().getCriteriaBuilder(); CriteriaQuery<Tuple> criteria = builder.createTupleQuery(); Root<PreVenda> root = criteria.from(PreVenda.class); // 日期转YYYYMMDD格式字符串,再转Long Expression<String> dataPrevVendaStr = builder.function( "TO_CHAR", String.class, root.get(PreVenda_.dataPrevVenda), builder.literal("YYYYMMDD") ); Expression<Long> dataPrevVendaNum = dataPrevVendaStr.as(Long.class); Expression<String> dataRealVendaStr = builder.function( "TO_CHAR", String.class, root.get(PreVenda_.dataRealVenda), builder.literal("YYYYMMDD") ); Expression<Long> dataRealVendaNum = dataRealVendaStr.as(Long.class); criteria.select(builder.tuple(builder.diff(dataRealVendaNum, dataPrevVendaNum)));
3. PostgreSQL数据库
同样用TO_CHAR函数,逻辑和Oracle一致:
// 仅格式化部分代码差异,其余逻辑同上 Expression<String> dataPrevVendaStr = builder.function( "TO_CHAR", String.class, root.get(PreVenda_.dataPrevVenda), builder.literal("YYYYMMDD") );
额外提醒
- 如果你的需求是计算两个日期的天数差,而不是纯数字格式的日期差值,更推荐直接用数据库的日期差函数(比如MySQL的
DATEDIFF,Oracle的TRUNC(dataRealVenda) - TRUNC(dataPrevVenda)),这样更高效,还能避免格式转换的麻烦。 - 顺便提一句:你的实体类里
valorRealVenda标注了nullable = false,但数据库表中这个字段是NULL DEFAULT NULL,两者约束不一致,后续可能会出现持久化异常,建议调整成一致哦。
内容的提问来源于stack exchange,提问作者Mauro
相关产品推荐
相关产品推荐

