You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.28 07:29:21