使用JPA Criteria的lessThanOrEqualTo()比较时间时遇类型兼容错误求助
问题解决:JPA Criteria查询中datetime与time类型比较的兼容问题
错误原因分析
SQL Server中,直接通过JPA的as(LocalTime.class)转换datetime字段时,生成的SQL可能存在类型转换逻辑的冗余(先转datetime再转time),导致数据库认为比较的两边类型不兼容(一边为time,一边被误识别为datetime),触发The data types time and datetime are incompatible错误。
解决方案
方法一:直接调用数据库CAST函数转换字段类型
通过CriteriaBuilder.function()调用SQL Server的CAST函数,将datetime字段直接转为time类型,确保比较两边类型一致:
// 调用SQL Server的CAST函数,将数据库datetime字段转为time类型 Expression<LocalTime> timeFromDatabase = criteriaBuilder.function( "CAST", LocalTime.class, root.get("period"), criteriaBuilder.literal("time") ); // 处理请求参数:合并重复的plusMinutes调用,原代码累计加了60分钟 LocalTime periodToRequest = FormatUtils.getLocalDateTime(request.getPeriodTo(), "dd-MMM-yyyy HH:mm:ss") .toLocalTime() .plusMinutes(60); // 构建时间比较条件 Predicate predicate = criteriaBuilder.lessThanOrEqualTo(timeFromDatabase, periodToRequest);
方法二:转换为秒数值进行比较(彻底规避类型问题)
将时间部分转为当天的总秒数,用数值类型进行比较,完全避免类型兼容问题:
// 计算数据库字段时间的总秒数(时*3600 + 分*60 + 秒) Expression<Integer> dbTimeSeconds = criteriaBuilder.sum( criteriaBuilder.prod( criteriaBuilder.function("DATEPART", Integer.class, criteriaBuilder.literal("hour"), root.get("period")), 3600 ), criteriaBuilder.sum( criteriaBuilder.prod( criteriaBuilder.function("DATEPART", Integer.class, criteriaBuilder.literal("minute"), root.get("period")), 60 ), criteriaBuilder.function("DATEPART", Integer.class, criteriaBuilder.literal("second"), root.get("period")) ) ); // 计算请求目标时间的总秒数 LocalTime targetTime = FormatUtils.getLocalDateTime(request.getPeriodTo(), "dd-MMM-yyyy HH:mm:ss") .toLocalTime() .plusMinutes(60); int targetSeconds = targetTime.getHour() * 3600 + targetTime.getMinute() * 60 + targetTime.getSecond(); // 构建数值比较条件 Predicate predicate = criteriaBuilder.lessThanOrEqualTo(dbTimeSeconds, targetSeconds);
内容的提问来源于stack exchange,提问作者Duy Dang
相关产品推荐
相关产品推荐

