2016-10-24 8 views
0

Hibernate 5.1.1でjava.time.ZoneIdを文字列に永続的にマッピングする方法はありますか。 ZoneIdをバイナリ形式で保存します。java.lang.ThisIdからデータベースへのGrails(Hibernate)のマッピング

私はHibernate 5.1.1を持つGrails 3.2.1にアップグレードしました。例えばjava.time.Instantの保存は正常に動作しますが、java.time.ZoneIdはバイナリ形式でのみ保存されます。

私はHibernateからのサポートはないと思います。だから私はどのように私自身のマッピングをコーディングすることができます。私はJadira Frameworkを使用しようとしましたが、grailsアプリケーションを起動するときにいくつかの競合(例外)があります。

+1

はなぜZoneId.of( "するzoneid")を使用して、それを初期化、文字列としてzoneId.getId()を保存していませんか? – aviad

+0

これは実際に私の回避策ですが、どういうわけか私はそれが自動的に実行できると感じています。少なくともJadiraはそれをまさにそのようにしていました(私はGrails 3.1.9からGrails 3.2.1にアップグレードする前にそれを使っていました) – kuceram

+1

私は、変換を行うエンティティで常に@Transientメソッドを作ることができます文字列をゾーンIDに変換すると透明になります – aviad

答えて

0

最終的に、私はカスタムハイバネートユーザータイプを実装する良い方法を発見しました。 varchar型としてjava.time.ZoneIdを持続するには、次のユーザタイプのクラスを実装:

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では動作しません。私のカスタムUser Typeを実装するソリューションが見つかりました。下の私の答えを見てください。あなたはとにかく良い方向に私を指摘しました... – kuceram

+0

はい、あなたはいつもユーザータイプに行くことができますが、コンバータははるかに簡単です。 Grails 3で動作しなかった理由はありますか?私はそれに驚いています。 – Gunnar

+0

いいえGORMの洞察はありません... http://gorm.grails.org/latest/ – kuceram

関連する問題