Oracle Hibernate使用BigDecimal而不是Int
我让Oracle typeOracle Hibernate使用BigDecimal而不是Int,oracle,hibernate,jpa,kotlin,Oracle,Hibernate,Jpa,Kotlin,我让Oracle type将integer\u varray类型创建或替换为int的varray(4000)然后是使用此类型的表。(Oracle DB-12.1.0.2) hibernate中的实体将IntArray作为一个类型,并且IntArrayType来自这个库(实际上,它是库还是我自己的实现并不重要,两种情况下的行为都是相同的) 问题是Hibernate将此数组视为BigDecimal的数组,因此当Hibernate类型尝试将其强制转换为Int时,它会引发异常 如何强制Hibernate
将integer\u varray类型创建或替换为int的varray(4000)代码>然后是使用此类型的表。(Oracle DB-12.1.0.2)
hibernate中的实体将IntArray
作为一个类型,并且IntArrayType
来自这个库(实际上,它是库还是我自己的实现并不重要,两种情况下的行为都是相同的)
问题是Hibernate将此数组视为BigDecimal
的数组,因此当Hibernate类型尝试将其强制转换为Int
时,它会引发异常
如何强制Hibernate在此自定义类型中使用Int
而不是BigDecimal
?具有Int
的其他字段的行为与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()
类IntArrayOracleType:UserType{
覆盖乐趣汇编(缓存:可序列化?、所有者:任何?)=deepCopy(缓存)
override fun deepCopy(值:Any?=(anyToIntArraySafe(值))?.copyOf()
覆盖(值:任何?)=deepCopy(值)
覆盖乐趣等于(x:Any?,y:Any?=(x?.equals(y)?:y?.equals(x))?:真
重写有趣的hashCode(x:Any?=x?.hashCode()?:0
可重写()=true
重写fun nullSafeGet(resultSet:resultSet,
名称:数组?,
会话:SharedSessionCompactmentor?,
业主:有吗?):有吗{
if(resultSet.wasNull()| | names==null){
返回空
}
返回anyToIntArraySafe(resultSet.getArray(名称[0])?.array)?:intArrayOf()
}
重写nullSafeSet(语句:PreparedStatement,值:Any?,索引:Int,会话:SharedSessionCompactImplementor){
val connection=statement.connection
如果(值==null){
语句.setNull(索引,Types.ARRAY,“INTEGER\u VARRAY”)
}否则{
val oraConnection=connection.unwrap(OracleConnection::class.java)
val array=oraConnection.createOracleArray(“INTEGER_VARRAY”,value)
语句.setArray(索引,数组)
}
}
覆盖乐趣替换(原始:任意?,目标:任意?,所有者:任意?=(anyToIntArraySafe(原始))?.copyOf()
重写fun returnedClass()=IntArray::class.java
重写fun sqlTypes()=intArrayOf(Types.ARRAY)
}
/**
*吃点什么?并尝试将其强制转换为数组,而不是IntArray-已选中BigDecimal。
*
*请注意,当给定数组包含任何其他内容时,将抛出BigDecimal或Int异常
*@return IntArray如果成功铸造,则为null
* */
内部趣味anyToIntArraySafe(数组:Any?=(数组作为?IntArray)?:(数组作为?数组)?.map{
它是?Int?:(它是BigDecimal.intValueExact()
}?toIntArray()
这里将BigDecimal
转换为Int
。然后只需将IntArrayType
更改为IntArrayType
,现在它就可以工作了。这里有些代码可能会有所帮助。我添加了实体代码和SQL表定义