Массивы Oracle и гибернация

Настройка - Oracle 12.1.0.2, Kotlin, Hibernate

У меня есть таблица, которая была создана так:

create or replace type capacity_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 capacity_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
    }
}

Массив неправильно преобразован из базы данных, и я получил java.lang.ClassCastException: java.math.BigDecimal cannot be cast to java.lang.Integer, поэтому я попытался реализовать свой собственный преобразователь, реализующий UserType, но здесь я застрял с установкой массива в db.

Как правильно работать с этим массивом int? Как мне написать модель для этой конкретной таблицы и типа? Хотелось бы получить IntArray из этой области.

Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
0
0
419
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Решение состоит в том, чтобы получить 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()

А здесь приведите BigDecimal к Int. Затем просто измените IntArrayType на IntArrayOracleType, и теперь он работает.

Другие вопросы по теме