@LukasEder,这个问题与Kotlin更相关,你可以跳过它,转而关注https://github.com/jOOQ/jOOQ/issues/14972中与jOOQ更相关的部分:)
因此,遗留数据库的一部分具有相当过度的设计,但我们不能也不想在从JPA迁移到jOOQ的过程中改变这一点,并希望将其留到以后。
举个(可悲的多个例子中的一个):我们有Characteristic
。它们做什么并不重要,只是它们被键入了。
因为它们看起来非常相同,而且在某些时候,我们可能想要简化数据库,所以我们并不想为它们编写多个查询。
我们确定的解决方案是定义一个Map,该Map将为我们提供给定特定类型的正确表。
比如说
@Bean(CHARACTERISTIC_TABLE)
fun characteristicTable(): Map<CharacteristicType, Table<*>> = mapOf(
CharacteristicType.INTEGER to INTEGER_CHARACTERISTIC,
CharacteristicType.FLOAT to FLOAT_CHARACTERISTIC,
CharacteristicType.TEXT to TEXT_CHARACTERISTIC,
CharacteristicType.NOMINAL to NOMINAL_CHARACTERISTIC,
CharacteristicType.ORDINAL to ORDINAL_CHARACTERISTIC,
CharacteristicType.BINARY_PDF to BINARY_CHARACTERISTIC,
CharacteristicType.BINARY_IMAGE to BINARY_CHARACTERISTIC,
CharacteristicType.TABULAR to GROUP_CHARACTERISTIC
)
我们可以将其注入到我们的存储库中,并基于CharacteristicType
从中检索Table<*>
。
显然,Table<*>
不知道任何关于它的字段的信息,所以我们必须自己定义它们共享的列。例如:
private val Table<*>.ID get() = this.checkField<Int>("id")
private val Table<*>.NAME get() = this.checkField<String>("name")
何处
inline fun <reified T : Any> Table<*>.checkField(fieldName: String): Field<T> =
checkNotNull(this.field(fieldName, T::class.javaObjectType)) {
"Table [$this] lacks the '$fieldName' column."
}
当然,问题是现在 ALL 表都有一个e。例如.NAME
列建议,即使它们实际上没有name
列,因为它们都适合Table<*>
类型。
输入Kotlin value classes:通过定义一个 Package 器,我们可以定义扩展属性的范围,并且仍然让它们像任何旧的Table<*>
一样工作,而不需要支付任何 Package 开销。
即,对于我们的Characteristic
s,我们可以定义
@JvmInline
value class CharacteristicTable<T : Record>(val value: Table<T>) : Table<T> by value
把我们的table包在Map里
@Bean(CHARACTERISTIC_TABLE)
fun characteristicTable(): Map<CharacteristicType, CharacteristicTable<*>> = mapOf(
CharacteristicType.INTEGER to CharacteristicTable(INTEGER_CHARACTERISTIC),
CharacteristicType.FLOAT to CharacteristicTable(FLOAT_CHARACTERISTIC),
CharacteristicType.TEXT to CharacteristicTable(TEXT_CHARACTERISTIC),
CharacteristicType.NOMINAL to CharacteristicTable(NOMINAL_CHARACTERISTIC),
CharacteristicType.ORDINAL to CharacteristicTable(ORDINAL_CHARACTERISTIC),
CharacteristicType.BINARY_PDF to CharacteristicTable(BINARY_CHARACTERISTIC),
CharacteristicType.BINARY_IMAGE to CharacteristicTable(BINARY_CHARACTERISTIC),
CharacteristicType.TABULAR to CharacteristicTable(GROUP_CHARACTERISTIC)
)
然后在
private val CharacteristicTable<*>.ID get() = this.checkField<Int>("id")
private val CharacteristicTable<*>.NAME get() = this.checkField<String>("name")
private val CharacteristicTable<*>.MACHINE_CODE get() = this.checkField<String>("machine_code")
[...]
同时仍然使用它们作为Table<*>
,它们在我们的查询中 Package :
val characteristic: CharacteristicTable<*> = [...]
val ctx: DSLContext = [...]
[...]
val intId = ctx
.insertInto(characteristic) //our wrapped table, used to be the actual Table<*>
.columns(*insertedColumns)
.values(*insertedValues)
.onConflict(characteristic.MACHINE_CODE)
.doUpdate()
.setAllToExcluded()
.returning(characteristic.ID)
.fetchSingle { it[characteristic.ID] }
[...]
至少我是这么想的
但是,如果我们这样做,问题是上面的查询将抛出一个
java.lang.ClassCastException: class my.app.db.config.QualifiedMaps$CharacteristicTable cannot be cast to class org.jooq.QueryPartInternal (my.app.db.config.QualifiedMaps$CharacteristicTable and org.jooq.QueryPartInternal are in unnamed module of loader 'app')
at org.jooq_3.18.0.POSTGRES.debug(Unknown Source)
at org.jooq.impl.AbstractContext.visit(AbstractContext.java:292)
at org.jooq.impl.InsertQueryImpl.lambda$toSQLInsert$11(InsertQueryImpl.java:700)
at org.jooq.impl.AbstractContext.toggle(AbstractContext.java:379)
at org.jooq.impl.AbstractContext.declareTables(AbstractContext.java:623)
at org.jooq.impl.InsertQueryImpl.toSQLInsert(InsertQueryImpl.java:700)
at org.jooq.impl.InsertQueryImpl.lambda$accept0$1(InsertQueryImpl.java:389)
at org.jooq.impl.AbstractContext.toggle(AbstractContext.java:393)
at org.jooq.impl.AbstractContext.data(AbstractContext.java:404)
at org.jooq.impl.InsertQueryImpl.accept0(InsertQueryImpl.java:389)
at org.jooq.impl.AbstractDMLQuery.accept(AbstractDMLQuery.java:670)
at org.jooq.impl.DefaultRenderContext.visit0(DefaultRenderContext.java:726)
at org.jooq.impl.AbstractContext.visit(AbstractContext.java:350)
at org.jooq.impl.AbstractQuery.getSQL0(AbstractQuery.java:491)
at org.jooq.impl.AbstractQuery.execute(AbstractQuery.java:300)
at org.jooq.impl.AbstractDMLQueryAsResultQuery.fetch(AbstractDMLQueryAsResultQuery.java:140)
at org.jooq.impl.ResultQueryTrait.fetchLazy(ResultQueryTrait.java:281)
at org.jooq.impl.ResultQueryTrait.fetchLazyNonAutoClosing(ResultQueryTrait.java:290)
at org.jooq.impl.ResultQueryTrait.fetchSingle(ResultQueryTrait.java:605)
at org.jooq.impl.ResultQueryTrait.fetchSingle(ResultQueryTrait.java:610)
为什么Kotlin类没有内联?
从文档中,我们知道:
根据经验,内联类无论何时用作另一种类型都将被装箱。
这就是我们的答案(有点)。
我们当然可以手动取消装箱,但这就违背了使用值类的目的。..
我们可以对类做些什么来强制Kotlin总是内联它吗?
1条答案
按热度按时间c3frrgcw1#
这并没有回答你关于内联类型的实际问题,但我认为你的问题可以用不同的方式解决,正如我在你创建和链接的issue #14972上所说的那样。
不要 Package jOOQ生成的表,只需让jOOQ生成的表扩展您的类型:
您可以:
CharacteristicsTable<R : Record> : Table<R>
接口