【发布时间】:2016-11-02 09:49:38
【问题描述】:
我们对 Hibernate 的 ZonedDateTime 用户类型不满意,因为它们不保留 ZoneId。
因此,我们创建了一个 CompositeUserType,它同时存储为时间戳和字符串,类似于:
public class ZonedDateTimeUserType implements CompositeUserType {
public static final String PROPERTY_NAME_TIMESTAMP = "zonedDateTime";
public static final String PROPERTY_NAME_ZONEID = "zoneId";
private static final Type[] SQL_TYPES = {TimestampType.INSTANCE, StringType.INSTANCE};
private static final String[] PROPERTY_NAMES = {PROPERTY_NAME_TIMESTAMP, PROPERTY_NAME_ZONEID};
@Override
public Object nullSafeGet(final ResultSet resultSet, final String[] names, final SessionImplementor sessImpl, final Object owner)
throws SQLException {
assert names.length == 2;
Timestamp date = resultSet.getTimestamp(names[0]);
if (date == null) {
return null;
}
ZoneId zoneId = ZoneId.of(resultSet.getString(names[1]));
return getZonedDateTime4Timestamp(date, zoneId);
}
@Override
public void nullSafeSet(final PreparedStatement preparedStatement, final Object value, final int index, final SessionImplementor sessImpl)
throws SQLException {
if (null == value) {
TimestampType.INSTANCE.set(preparedStatement, null, index, sessImpl);
StringType.INSTANCE.set(preparedStatement, null, index + 1, sessImpl);
} else {
ZonedDateTime zonedDateTime = (ZonedDateTime) value;
TimestampType.INSTANCE.set(preparedStatement, getTimestamp4ZonedDateTime(zonedDateTime), index, sessImpl);
StringType.INSTANCE.set(preparedStatement, zonedDateTime.getZone().getId(), index + 1, sessImpl);
}
}
private ZonedDateTime getZonedDateTime4Timestamp(final Timestamp ts, final ZoneId zoneId) {
Instant instant = Instant.ofEpochMilli(ts.getTime());
return ZonedDateTime.ofInstant(instant, zoneId);
}
private Timestamp getTimestamp4ZonedDateTime(final ZonedDateTime zonedDateTime) {
return Timestamp.from(zonedDateTime.toInstant());
}
[...]
}
用作
@Columns(columns = {@Column(name = "createdAt"), @Column(name = "createdAtZone")})
@Type(type = ZONED_DATE_TIME_USER_TYPE)
private ZonedDateTime createdAt;
问题是只在 Timestamp 列上创建条件查询。
使用 Hibernates 标准 API 很容易:
Restrictions.ge("createdAt.zonedDateTime", Date.from(filter.getCreatedAt().toInstant()))
但到目前为止,我们所有使用 JPA 标准 API 的尝试都失败了。我们尝试了什么是:
cb.greaterThanOrEqualTo(root.get(Entity_.createdAt).get("zonedDateTime"), filter.getCreatedAt())
cb.greaterThanOrEqualTo(root.get("createdAt.zonedDateTime"), filter.getCreatedAt())
【问题讨论】: