postgresql - 如何使用 Kotlin 的 Ktorm 对自定义 Postgres“对象类型”执行 WHERE 子句操作,避免“PSQLException:错误:运算符不存在”
问题描述
在对自定义 Postgres“对象类型”执行 WHERE 子句操作时,我结束了以下 PSQLException。
- 语言:科特林。
- ORM 库:Ktorm ORM。
例外
org.postgresql.util.PSQLException: ERROR: operator does not exist: rate = character varying
Hint: No operator matches the given name and argument types. You might need to add explicit type casts.
我在这里遵循了 Ktorm 官方指南,但是没有提到自定义 Postgres 类型。任何指针/帮助将不胜感激。请参阅下面的代码以重现:
谢谢你。
- 会产生上述异常的示例测试
internal class SuppliersInstanceDAOTest {
@Test
fun shouldReturnInstanceSequence() {
val database = Database.connect("jdbc:postgresql://localhost:5432/mydb", user = "postgres", password = "superpassword")
val instanceDate: LocalDate = LocalDate.of(2019, 4, 1)
database.withSchemaTransaction("suppliers") {
database.from(SuppliersInstanceTable)
.select(SuppliersInstanceTable.instanceSeq)
.whereWithConditions {
// The following line causes "ERROR: operator does not exist: rate = character varying"
it += SuppliersInstanceTable.rate eq Rate.DAILY
}.asIterable()
.first()
.getInt(1)
}
}
}
- 架构
-- Note the special custom enum object type here that I cannot do anything about
CREATE TYPE suppliers.rate AS ENUM
('Daily', 'Byweekly');
CREATE TABLE suppliers.instance
(
rate suppliers.rate NOT NULL,
instance_value integer NOT NULL
)
TABLESPACE pg_default;
- Kotlin 的 Ktorms 实体和绑定
enum class Rate(val value: String) {
DAILY("Daily"),
BIWEEKLY("Byweekly")
}
interface SuppliersInstance : Entity<SuppliersInstance> {
companion object : Entity.Factory<SuppliersInstance>()
val rate: Rate
val instanceSeq: Int
}
object SuppliersInstanceTable : Table<SuppliersInstance>("instance") {
val rate = enum("rate", typeRef<Rate>()).primaryKey().bindTo { it.rate } // <-- Suspect
//val rate = enum<Rate>("rate", typeRef()).primaryKey().bindTo { it.rate } // Failed too
val instanceSeq = int("instance_value").primaryKey().bindTo { it.instanceSeq }
}
解决方案
在寻求 Ktorm 维护人员的帮助后,事实证明,较新版本的 ktorm 支持原生 Postgressql 枚举对象类型。在我的情况下,我需要pgEnum
代替enum
将枚举转换为 varchar 的默认 ktrom 函数,从而导致 Postressql 中的类型冲突:
但是,在编写 ktorm 的 pgEnum 函数时请注意,仅在 ktorm v3.2.x + 中。Jcentral和mavenCentral maven 存储库中可用的最新版本是 v3.1.0。这是因为在最新版本中还有一个组名从 更改me.liuwj.ktorm
为。org.ktorm
因此,升级还意味着更改依赖项中的组名以使新组名与 maven 存储库匹配。这是我项目的无缝升级,新的 pgEnum 在我的用例中工作。
对于我上面的代码示例,这意味着交换这个
object SuppliersInstanceTable : Table<SuppliersInstance>("instance") {
val rate = enum("rate", typeRef<Rate>()).primaryKey().bindTo { it.rate } <---
...
}
为了
object SuppliersInstanceTable : Table<SuppliersInstance>("instance") {
val rate = pgEnum<Rate>("rate").primaryKey().bindTo { it.rate } <---
...
}