Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/hibernate/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/jpa/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Grails(Hibernate)将java.time.ZoneId映射到数据库_Hibernate_Jpa_Grails_Grails 3.0_Hibernate 5.x - Fatal编程技术网

Grails(Hibernate)将java.time.ZoneId映射到数据库

Grails(Hibernate)将java.time.ZoneId映射到数据库,hibernate,jpa,grails,grails-3.0,hibernate-5.x,Hibernate,Jpa,Grails,Grails 3.0,Hibernate 5.x,有没有办法在Hibernate 5.1.1中支持java.time.ZoneId到字符串的持久映射。它现在以二进制形式保存ZoneId 我刚刚升级到Grails3.2.1,它有Hibernate5.1.1。例如,保存java.time.Instant可以很好地工作,但是java.time.ZoneId仅以二进制形式存储 我认为Hibernate不支持。那么我如何编写自己的映射呢。我尝试过使用,但不可能,因为启动grails应用程序时存在一些冲突(例外)。您可以使用JPA 2.1定义的自定义属性转

有没有办法在Hibernate 5.1.1中支持java.time.ZoneId到字符串的持久映射。它现在以二进制形式保存ZoneId

我刚刚升级到Grails3.2.1,它有Hibernate5.1.1。例如,保存java.time.Instant可以很好地工作,但是java.time.ZoneId仅以二进制形式存储


我认为Hibernate不支持。那么我如何编写自己的映射呢。我尝试过使用,但不可能,因为启动grails应用程序时存在一些冲突(例外)。

您可以使用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
属性时,转换器将自动调用。

因此我终于找到了一种实现自定义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
}
见:

  • 您可以使用库,然后只需编写

    @列
    私人区;
    
    在实体类中。必须使用此注释标记实体类:

    @TypeDef(typeClass=ZoneIdType.class,defaultForType=ZoneId.class)
    
    为什么不将zoneId.getId()保存为字符串,然后使用zoneId.of(“zoneId”)初始化它?这实际上是我的解决方法,但不知何故,我觉得它可以自动完成。至少Jadira是这样做的(我在从Grails 3.1.9升级到Grails 3.2.1之前就用过),我知道,你可以在实体中创建一个@Transient方法来完成从字符串到区域id的转换,所以它是透明的。我以前见过这个,但是它在使用Hibernate 5的Grails 3中不起作用。我找到了实现自定义用户类型的解决方案。见下面我的答案。不管怎样,你给我指出了一个好的方向……是的,你总是可以选择用户类型,尽管转换器要简单得多。你有没有任何细节说明为什么它在Grails3中不起作用?我对此感到惊讶。
    import java.time.ZoneId
    
    class MyDomain {
        ZoneId zoneId
    }