首页 > 解决方案 > 如何使用 Kotlin 的 Ktorm 对自定义 Postgres“对象类型”执行 WHERE 子句操作,避免“PSQLException:错误:运算符不存在”

问题描述

在对自定义 Postgres“对象类型”执行 WHERE 子句操作时,我结束了以下 PSQLException。

例外

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 类型。任何指针/帮助将不胜感激。请参阅下面的代码以重现:

谢谢你。

  1. 会产生上述异常的示例测试
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)
        }
        
    }
}
  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;

  1. 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 }
}

标签: postgresqlkotlinormoperationkotlin-dsl

解决方案


在寻求 Ktorm 维护人员的帮助后,事实证明,较新版本的 ktorm 支持原生 Postgressql 枚举对象类型。在我的情况下,我需要pgEnum代替enum将枚举转换为 varchar 的默认 ktrom 函数,从而导致 Postressql 中的类型冲突:

在此处参考 pgEnum

但是,在编写 ktorm 的 pgEnum 函数时请注意,仅在 ktorm v3.2.x + 中。JcentralmavenCentral 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 } <---
    ...
}

推荐阅读