如何注册多个JDBC类型。为Hibernate本机SQL查询构建标量投影时的其他映射

问题描述 投票:0回答:1

我想使用来自hibernate-types-52(@Vlad Mihalcea)的UUID和Range类型进行冬眠本机标量投影(使用Tuple.class)。

我正在使用:

  • spring boot(v2.2.6.RELEASE)
  • 休眠(v5.4.12.Final)
  • hibernate-types-52(v2.9.7)
  • postgres(v11)

我已经声明了自定义的PostgreSQL方言

class CustomPostgreSQLDialect : PostgreSQL10Dialect() {

    init {
        this.registerColumnType(Types.BLOB, "bytea");
        this.registerHibernateType(Types.OTHER, PostgresUUIDType::class.java.name)
        //this.registerHibernateType(Types.OTHER, PostgreSQLRangeType::class.java.name)
    }

    override fun remapSqlTypeDescriptor(sqlTypeDescriptor: SqlTypeDescriptor): SqlTypeDescriptor {
        return if (sqlTypeDescriptor.sqlType == Types.BLOB) {
            BinaryTypeDescriptor.INSTANCE
        } else super.remapSqlTypeDescriptor(sqlTypeDescriptor)
    }
}

当下一行是注释时

this.registerHibernateType(Types.OTHER, PostgreSQLRangeType::class.java.name)

[并且仅当我投射范围列时,它才能正常工作。

val statement = "SELECT uuidColumn, CAST(rangeColumn as TEXT) FROM ...."
entityManager.createNativeQuery(statement, Tuple::class.java)

如果我是对的,我只能为java.sql.Types.OTHER声明一个映射,如果我声明多个,则使用最后一个。确实,如果两者都不加注释,则我有一个ClassCastException,因为UUID无法转换为PGObject。

是否有一种方法可以使用UUID和Range类型进行本机标量投影(使用Tuple.class),而无需强制转换一个或另一个?最后,我想像下面这样写我的查询

val statement = "SELECT uuidColumn, rangeColumn FROM ...."
entityManager.createNativeQuery(statement, Tuple::class.java)

我知道以下选项

@SqlResultSetMapping(
  name="ProjectioName",
  columns=[
    ColumnResult(name="uuidColumn", type = PostgresUUIDType::class),
    ColumnResult(name="rangeColumn", type = PostgreSQLRangeType::class)
  ]
)

entityManager.createNativeQuery(statement, "ProjectioName")

问题是我不想为所有具有UUID和其他特定列(JSON,Range,...)的投影声明'SqlResultSetMapping'。

entityManager.createNativeQuery(statement, Tuple::class.java)
  .unwrap(NativeQuery::class.java)
  .addScalar("uuidColumn", PostgresUUIDType.INSTANCE)
  .addScalar("rangeColumn", PostgreSQLRangeType.INSTANCE)

此选项可能很好,但是我有很多列,如果我开始添加“ .addScalar(...)”,则需要定义所有列。从概念上讲,我想对某些特定的列使用“ .addScalar(...)”,对于那些我未声明的列,则使用默认的“策略”,这可能吗?

postgresql hibernate jpa projection hibernate-types
1个回答
0
投票

这是一个非常常见的问题,所以此答案基于我之前写的this article

问题

JDBC Types interface定义了所有常见的SQL列类型,例如TypesVARCHARINTEGER

但是,对于特定于数据库的列,只有DATE条目可以引用它们。

因此,如果您的一个表同时定义了Types.OTHER列和UUID列,那么,当您从该表中获取行时,这两个列都将使用Range JDBC类型。

因此,您不能注册默认的休眠类型来覆盖Range,因为根据数据库特定的列类型,您需要不同的类型。

解决方案

您需要在查询级显式定义Hibernate Types.OTHER

Types.OTHER

现在,您的问题是:

此选项可能很好,但是如果我开始的话,我会有很多列添加了“ .addScalar(...)”,我需要定义所有列。

而且,有解决方案。

您可以使用Type动态建立查询。基于List<Tuple> tuples = entityManager .createNativeQuery( "SELECT uuidColumn, CAST(rangeColumn as TEXT) " + "FROM book ", Tuple.class) .unwrap(org.hibernate.query.NativeQuery.class) .addScalar("uuidColumn", PostgresUUIDType.INSTANCE) .addScalar("rangeColumn", PostgreSQLRangeType.INSTANCE) .getResultList(); ,可以在构建投影查询时应用正确的Hibernate Criteria API

© www.soinside.com 2019 - 2024. All rights reserved.