所以我終於找到了一個很好的方法來實現自定義的hibernate用戶類型。堅持java.time.ZoneId爲varchar實施下列用戶類型的類:
import org.hibernate.HibernateException
import org.hibernate.engine.spi.SessionImplementor
import org.hibernate.type.StandardBasicTypes
import org.hibernate.usertype.EnhancedUserType
import java.sql.PreparedStatement
import java.sql.ResultSet
import java.sql.SQLException
import java.sql.Types
import java.time.ZoneId
/**
* A type that maps between {@link java.sql.Types#VARCHAR} and {@link ZoneId}.
*/
class ZoneIdUserType implements EnhancedUserType, Serializable {
private static final int[] SQL_TYPES = [Types.VARCHAR]
@Override
public int[] sqlTypes() {
return SQL_TYPES
}
@Override
public Class returnedClass() {
return ZoneId.class
}
@Override
public boolean equals(Object x, Object y) throws HibernateException {
if (x == y) {
return true
}
if (x == null || y == null) {
return false
}
ZoneId zx = (ZoneId) x
ZoneId zy = (ZoneId) y
return zx.equals(zy)
}
@Override
public int hashCode(Object object) throws HibernateException {
return object.hashCode()
}
@Override
public Object nullSafeGet(ResultSet resultSet, String[] names, SessionImplementor session, Object owner)
throws HibernateException, SQLException {
Object zoneId = StandardBasicTypes.STRING.nullSafeGet(resultSet, names, session, owner)
if (zoneId == null) {
return null
}
return ZoneId.of(zoneId)
}
@Override
public void nullSafeSet(PreparedStatement preparedStatement, Object value, int index, SessionImplementor session)
throws HibernateException, SQLException {
if (value == null) {
StandardBasicTypes.STRING.nullSafeSet(preparedStatement, null, index, session)
} else {
def zoneId = (ZoneId) value
StandardBasicTypes.STRING.nullSafeSet(preparedStatement, zoneId.getId(), index, session)
}
}
@Override
public Object deepCopy(Object value) throws HibernateException {
return value
}
@Override
public boolean isMutable() {
return false
}
@Override
public Serializable disassemble(Object value) throws HibernateException {
return (Serializable) value
}
@Override
public Object assemble(Serializable cached, Object value) throws HibernateException {
return cached
}
@Override
public Object replace(Object original, Object target, Object owner) throws HibernateException {
return original
}
@Override
public String objectToSQLString(Object object) {
throw new UnsupportedOperationException()
}
@Override
public String toXMLString(Object object) {
return object.toString()
}
@Override
public Object fromXMLString(String string) {
return ZoneId.of(string)
}
}
然後,你需要在你的Grails應用的conf/application.groovy
註冊自定義用戶類型:
grails.gorm.default.mapping = {
'user-type'(type: ZoneIdUserType, class: ZoneId)
}
比你可以簡單地用java .time.ZoneId在您的域類:
import java.time.ZoneId
class MyDomain {
ZoneId zoneId
}
參見:
- http://docs.grails.org/latest/ref/Database%20Mapping/Usage.html
- http://blog.progs.be/550/java-time-hibernate
爲什麼不保存zoneId.getId()作爲字符串,然後初始化它使用ZoneId.of( 「了zoneid」)? – aviad
這實際上是我的解決方法,但不知何故,我覺得它可以自動完成。至少Jadira是這樣做的(我在從Grails 3.1.9升級到Grails 3.2.1之前已經使用過) – kuceram
我明白,你可以在實體中做一個@Transient方法來完成從字符串到區域ID,所以它將是透明的 – aviad