Hibernate 使用 BigDecimal 而不是 Int

卢卡斯·福斯特

我有 Oracle 类型create or replace type integer_varray as varray (4000) of int;,然后是使用这种类型的表。(Oracle 数据库 - 12.1.0.2)

hibernate 中的实体具有IntArray类型,并且IntArrayType来自该库https://github.com/vladmihalcea/hibernate-types(实际上无论是库还是我自己的实现,这两种情况的行为都相同)。

问题是 Hibernate 将此数组视为数组,BigDecimal因此当 hibernate-types 尝试将其强制转换为Int.

如何强制 Hibernate 使用Int而不是BigDecimal在此自定义类型中使用?其他字段Int作为整数正确运行,但这种特殊类型不是。

一些代码: SQL 表:

create or replace type integer_varray as varray (4000) of int;
create table plan_capacities
(
  id       int generated by default as identity not null constraint plan_capacities_pkey primary key,
  line_id  int references lines (id) on delete cascade,
  model_id int references models (id) on delete cascade,
  plan_id  int references plans (id) on delete cascade,
  capacity integer_varray
);

实体:

@Entity()
@Table(name = "plan_capacities")
@TypeDefs(
        TypeDef(name = "int-array", typeClass = IntArrayType::class)
)
data class PlanCapacity(
        @Id
        @GeneratedValue(strategy = GenerationType.IDENTITY)
        val id: Int,

        @ManyToOne
        @JoinColumn(name = "line_Id")
        val line: Line,

        @ManyToOne()
        @JoinColumn(name = "model_Id")
        val model: Model,

        @JsonBackReference
        @ManyToOne()
        @JoinColumn(name = "plan_id")
        val plan: Plan,

        @Column(name = "capacity")
        @Type(type = "int-array")
        val capacity: IntArray
) {
    override fun equals(other: Any?): Boolean {
        if (this === other) return true
        if (javaClass != other?.javaClass) return false

        other as PlanCapacity

        if (id != other.id) return false
        if (line != other.line) return false
        if (model != other.model) return false
        if (plan != other.plan) return false
        if (!Arrays.equals(capacity, other.capacity)) return false

        return true
    }

    override fun hashCode(): Int {
        var result = id
        result = 31 * result + line.hashCode()
        result = 31 * result + model.hashCode()
        result = 31 * result + plan.hashCode()
        result = 31 * result + Arrays.hashCode(capacity)
        return result
    }
}
卢卡斯·福斯特

解决方案是导出UserType

class IntArrayOracleType : UserType {
    override fun assemble(cached: Serializable?, owner: Any?) = deepCopy(cached)

    override fun deepCopy(value: Any?) = (anyToIntArraySafe(value))?.copyOf()

    override fun disassemble(value: Any?) = deepCopy(value)

    override fun equals(x: Any?, y: Any?) = (x?.equals(y) ?: y?.equals(x)) ?: true

    override fun hashCode(x: Any?) = x?.hashCode() ?: 0

    override fun isMutable() = true

    override fun nullSafeGet(resultSet: ResultSet,
                             names: Array<out String>?,
                             session: SharedSessionContractImplementor?,
                             owner: Any?): Any? {
        if (resultSet.wasNull() || names == null) {
            return null
        }

        return anyToIntArraySafe(resultSet.getArray(names[0])?.array) ?: intArrayOf()
    }

    override fun nullSafeSet(statement: PreparedStatement, value: Any?, index: Int, session: SharedSessionContractImplementor) {
        val connection = statement.connection
        if (value == null) {
            statement.setNull(index, Types.ARRAY, "INTEGER_VARRAY")
        } else {
            val oraConnection = connection.unwrap(OracleConnection::class.java)
            val array = oraConnection.createOracleArray("INTEGER_VARRAY", value)
            statement.setArray(index, array)
        }
    }

    override fun replace(original: Any?, target: Any?, owner: Any?) = (anyToIntArraySafe(original))?.copyOf()

    override fun returnedClass() = IntArray::class.java

    override fun sqlTypes() = intArrayOf(Types.ARRAY)
}

/**
 * Takes Any? and tries to cast it to Array and than to IntArray - BigDecimal is checked.
 *
 * Note that when given array contains anything else then BigDecimal or Int exception will be thrown
 * @return IntArray if successfully casted, null otherwise
 * */
internal fun anyToIntArraySafe(array: Any?) = (array as? IntArray) ?: (array as? Array<*>)?.map {
    it as? Int ?: (it as BigDecimal).intValueExact()
}?.toIntArray()

并在这里投射BigDecimalInt. 然后只需更改IntArrayTypeIntArrayOracleType现在它就可以工作了。

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章

Nashorn不再使用BigDecimal

为什么Java API使用int而不是short或byte?

JUnit使用BigDecimal声明

如何使用hibernate.properties文件而不是hibernate.cfg.xml

Java:为什么在现实世界中我们应该使用BigDecimal而不是Double?

使用BigDecimal作为初学者而不是Double?

在Java中比较BigDecimal和int

为什么要使用int [] a = new int [1]而不是仅仅使用int a?

Hibernate-BigDecimal映射精度

使用分页时,EntityManager.createNativeQuery返回对象列表而不是BigDecimal列表

返回Optional <User>而不是其中的Optional <BigDecimal>

BigDecimal.setScale(int,int)和RoundingMode枚举不推荐使用的构造函数

为什么Realm使用RealmOptional <Int>而不是Int?可选属性?

如何在for循环而不是int中使用double?

JOOQ总和字段值:BigDecimal到Int

Scala:Int到BigDecimal的转换?

如何将Int转换为BigDecimal?

使用postgres表序列而不是共享hibernate_sequence

为什么要使用“ int input {0};” 而不是“ int intput”;

BigDecimal中的NumberFormatException为int或long(java)

使用double而不是int循环

使用long而不是int时更快的程序

SQL使用强制转换而不是int字段

不同数字的Hibernate BigDecimal转换错误

提取BigDecimal的int部分?

使用Hibernate Mapping而不是使用Hibernate Annotations从Postgres读取Blob

JPA Hibernate 使用合并进行插入而不是更新

Hibernate Search 中 BigDecimal 的范围查询

使用 Random_int 而不是 Rand()