2016-10-24 156 views
0

有什麼辦法可以支持Hibernate 5.1.1中java.time.ZoneId持久映射到字符串嗎?它現在以二進制形式保存ZoneId。Grails(Hibernate)將java.time.ZoneId映射到數據庫

我剛升級到具有Hibernate 5.1.1的Grails 3.2.1。保存java.time.Instant例如可以正常工作,但java.time.ZoneId只能以二進制形式存儲。

我認爲Hibernate沒有支持。那麼我如何編碼我自己的映射。我試過使用Jadira Framework,但這不可能,因爲在啓動grails應用程序時有一些衝突(例外)。

+1

爲什麼不保存zoneId.getId()作爲字符串,然後初始化它使用ZoneId.of( 「了zoneid」)? – aviad

+0

這實際上是我的解決方法,但不知何故,我覺得它可以自動完成。至少Jadira是這樣做的(我在從Grails 3.1.9升級到Grails 3.2.1之前已經使用過) – kuceram

+1

我明白,你可以在實體中做一個@Transient方法來完成從字符串到區域ID,所以它將是透明的 – aviad

回答

0

所以我終於找到了一個很好的方法來實現自定義的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 
} 

參見:

  1. http://docs.grails.org/latest/ref/Database%20Mapping/Usage.html
  2. http://blog.progs.be/550/java-time-hibernate
0

您可以使用JPA 2.1定義的自定義屬性轉換器。聲明轉換器類,像這樣:

@Converter 
public static class ZoneIdConverter implements AttributeConverter<ZoneId, String> { 

    @Override 
    public String convertToDatabaseColumn(ZoneId attribute) { 
     return attribute.getId(); 
    } 

    @Override 
    public ZoneId convertToEntityAttribute(String dbData) { 
     return ZoneId.of(dbData); 
    } 
} 

,然後請參閱從ZoneId類型的實體屬性給它:

@Convert(converter = ZoneIdConverter.class) 
private ZoneId zoneId; 

持續/加載zoneId屬性時,轉換器將自動被調用。

+0

我以前見過這個,但它在使用Hibernate 5的Grails 3中不起作用。我找到了實現我的自定義用戶類型的解決方案。請參閱下面的答案。無論如何,你指出我的方向是好的...... – kuceram

+0

是的,你總是可以選擇用戶類型,儘管轉換器要簡單得多。你有沒有任何細節爲什麼在Grails 3中不起作用?我對此感到驚訝。 – Gunnar

+0

不,我對GORM沒有任何見解...... http://gorm.grails.org/latest/ – kuceram