2016-10-24 14 views
0

Есть ли способ поддерживать постоянное отображение java.time.ZoneId для строки в Hibernate 5.1.1. Теперь он сохраняет ZoneId в двоичной форме.Grails (Hibernate) Сопоставление java.time.ZoneId с базой данных

Я только что обновился до Grails 3.2.1, который имеет Hibernate 5.1.1. Сохранение java.time.Instant, например, работает отлично, но java.time.ZoneId сохраняется только в двоичной форме.

Я думаю, что нет поддержки от Hibernate. Итак, как я могу кодировать собственное сопоставление. Я пытался использовать Jadira Framework, но это невозможно, так как есть некоторые конфликты (исключения) при запуске приложения grails.

+1

почему не спасая zoneId.getId() в виде строки, а затем инициализации его с помощью ZoneId.of ("ZoneId")? – aviad

+0

Это на самом деле мое обходное решение, но почему-то я чувствую, что это можно сделать автоматически. По крайней мере, Джадира делала это точно так же (я использовал это до обновления от Grails 3.1.9 до Grails 3.2.1) – kuceram

+1

Насколько я понимаю, вы всегда можете сделать метод @Transient в сущности, которая будет выполнять преобразование из string to zone id, поэтому он будет прозрачным – aviad

ответ

0

Итак, я наконец нашел хороший способ, как реализовать пользовательские типы пользователей спящего режима. Чтобы сохранить 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) 
    } 
} 

Затем вам нужно зарегистрировать пользовательский тип пользователя в conf/application.groovy вашего приложения Grails:

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

Я видел это раньше, однако он не работает в Grails 3, который использует Hibernate 5. Я нашел решение, реализующее мой пользовательский тип пользователя. См. Мой ответ ниже. Вы все равно указали мне на хорошее направление ... – kuceram

+0

Да, вы всегда можете выбрать тип пользователя, хотя конвертер намного проще. У вас есть какие-либо подробности, почему он не работал в Grails 3? Я удивлен этим. – Gunnar

+0

Нет У меня нет информации о GORM ... http://gorm.grails.org/latest/ – kuceram