7

我有一个具有 DateTime 属性的实体与休眠状态保持一致

@Type(type = "org.jadira.usertype.dateandtime.joda.PersistentDateTime")
@Column(name = "EFF_DT")
protected DateTime effDt;

这一切都适用于常规 spring-data-jpa 生成的查询。

我正在尝试添加自定义本机查询

 @Query(value = "SELECT COUNT(*) FROM wsa_circuit_state_history ch WHERE ch.eff_dt between ?1 and ?2", nativeQuery = true)
    Integer countEffDateBetween(DateTime start, DateTime end);

我得到的错误是尝试调用它时

 java.sql.SQLException: ORA-00932: inconsistent datatypes: expected DATE got BINARY

这是我在将自定义类型映射添加到我的实体之前使用常规 spring-data 查找器遇到的相同错误

 @Type(type = "org.jadira.usertype.dateandtime.joda.PersistentDateTime")

如何让 spring-data-jpa/hibernate 使用自定义类型映射将参数映射到本机查询?

4

3 回答 3

1

正是我也有同样的要求。我通过将自定义类型注册到休眠配置来解决它。

对于原生查询,TypeDefs 不足以让 hibernate 找到用户类型。它需要类型解析器来找到它的类型。

@Query(value = "SELECT COUNT(*) FROM wsa_circuit_state_history ch WHERE ch.eff_dt between ?1 and ?2", nativeQuery = true)
    Integer countEffDateBetween(DateTime start, DateTime end);

在这种情况下,hibernate 会尝试从类型解析器中猜测类型(org.joda.time.DateTime)。

Type type = session.getFactory().getTypeResolver().heuristicType(typename);

由于 DateTime 没有解析器。然后它获取默认类型(可序列化类型)。并且 DateTime 的值被强制转换为它的类型,即在 DB 中被序列化并持久化,由于大二进制值而失败。

要解决此问题,您需要将 DateTime 类型注册到 Hibernate Configuration 为

configuration.registerTypeOverride(new org.jadira.usertype.dateandtime.joda.PersistentDateTime(), new String[]{"org.joda.time.DateTime"});
于 2015-07-27T07:40:57.797 回答
0

在类似的情况下,我求助于编写一个自定义 CompositeUserType,它将 Joda DateTime 存储在两个字段中,一个日期时间字段和一个时区字段。

当实体被保存时,它将时间值存储在 UTC 和时区作为原始值,在检索时它执行相反的操作(即,它将存储在数据库中的时间转换回原始时区)。

正如您在上面所确定的,尽管像“dateTime BETWEEN ?1 AND ?2”这样的查询具有直观意义,但对于复合类型当然没有意义,因为您需要牢记时区。这就是我以 UTC 格式存储所有值的原因,因此我可以随时比较数据库中的任意两个日期/时间值。

不幸的是,这意味着我传递的所有日期/时间查询参数都必须转换为 UTC。

于 2015-01-06T15:46:27.553 回答
0

只需像这样将您的属性设置为 java.util.Date

@Type(type = "org.jadira.usertype.dateandtime.joda.PersistentDateTime")
@Column(name = "EFF_DT")
@Temporal( TemporalType.TIMESTAMP )
protected Date effDt;

然后在你的 getter/setter 中转换

public DateTime getEffDt() {
    return null == effDt ? null : new DateTime( effDt );
}

public void setEffDt( final DateTime effDt ) {
    this.effDt = null == effDt ? null : effDt.toDate();
}

本国的:

@Query(value = "SELECT COUNT(*) FROM wsa_circuit_state_history ch WHERE ch.eff_dt between ?1 and ?2", nativeQuery = true)
Integer countEffDateBetween(Date start, Date end);
于 2014-08-01T15:02:34.430 回答