如何在Hibernate中将null转换为自定义@Type(PersistentDateTime)?
解决方案
针对当前环境(Spring 4.1.7 + Hibernate 4.2.5 + Java 7)
核心思路是让查询返回的null匹配PersistentDateTime/PersistentLocalDate对应的JDBC类型,同时显式告知Hibernate字段的类型映射:
1. 调整查询语句,将null转换为对应JDBC类型
- 对于
DateTime(对应PersistentDateTime),JDBC类型为TIMESTAMP,修改查询语句:// 用case处理分支,确保返回类型统一为TIMESTAMP sb.append(", case when :p_fooId is not null then (select foo.statusDate from Foo foo where foo.id = :p_fooId) else cast(null as timestamp) end as fooStatusDate"); - 对于
LocalDate(对应PersistentLocalDate),JDBC类型为DATE,修改为:sb.append(", case when :p_fooId is not null then (select foo.localDateField from Foo foo where foo.id = :p_fooId) else cast(null as date) end as fooStatusDate");
2. 查询时显式指定字段类型映射
在创建SQLQuery时,通过addScalar指定字段对应的Hibernate类型,确保null能被正确转换为Joda类型:
SQLQuery query = session.createSQLQuery(sb.toString()); query.setParameter("p_fooId", fooId); // 针对DateTime query.addScalar("fooStatusDate", new org.jadira.usertype.dateandtime.joda.PersistentDateTime()); // 针对LocalDate则替换为 // query.addScalar("fooStatusDate", new org.jadira.usertype.dateandtime.joda.PersistentLocalDate()); // 映射到DTO或实体 query.setResultTransformer(Transformers.aliasToBean(YourResultDTO.class));
3. 替代方案:使用子查询返回统一类型的null
如果不想用case语句,可以构造一个始终返回null的子查询,确保类型匹配:
// 针对DateTime,从Foo表取一个null的statusDate(利用表结构的类型) sb.append(", (select foo.statusDate from Foo foo where 1=0) as fooStatusDate");
这个子查询永远返回null,但类型和statusDate一致,Hibernate能直接识别并转换为Joda类型的null。
新版本方案(Hibernate 5.2+ + Java 8+)
放弃Jadira UserType,使用Hibernate原生的日期类型支持:
使用Java 8日期类型:将实体字段替换为
java.time.LocalDateTime/java.time.LocalDate,Hibernate 5.2+原生支持,无需额外Type注解:@Column(name = "STATUSDATE", nullable = false) private LocalDateTime statusDate;简化查询语句:直接使用
coalesce或直接返回null,Hibernate会自动处理类型映射:// 用coalesce处理,子查询无结果时返回null sb.append(", coalesce((select foo.statusDate from Foo foo where foo.id = :p_fooId), null) as fooStatusDate");若仍需使用Joda Time,Hibernate 5+提供
hibernate-joda模块,可直接使用内置类型,无需Jadira,查询时同样只需保证返回的null对应JDBC类型即可。
内容的提问来源于stack exchange,提问作者Nikolas
相关产品推荐
相关产品推荐

