java - 是否可以编写一个 jOOQ 转换器来应用于数组?

标签 java postgresql jooq pg-jdbc

我有一个 postgres 数据库,其中一些列的类型为 varchar[] . jOOQ 和 pgjdbc-ng 并没有很好地配合; jOOQ 的 DefaultBindContext 具有以下内容:

protected final BindContext bindValue0(Object value, Field<?> field) throws SQLException {
    SQLDialect dialect = configuration.dialect();

    // [#650] [#3108] Use the Field's Converter before actually binding any value
    Converter<?, ?> converter = field.getConverter();
    Class<?> type = converter.fromType();
    value = ((Converter) converter).to(value);

    //...

    else if (type.isArray()) {
        switch (dialect) {
            case POSTGRES: {
                stmt.setString(nextIndex(), toPGArrayString((Object[]) value));
                break;
            }

将语句变量设置为"{\"value1\", \"value2\", \"etc\"}" ,这就是您在查询中指定数组的方式。后来,pgjdbc-ng 有:

public static Object coerceToArray(Format format, Object val, Type type, Class<?> targetType, Map<String, Class<?>> typeMap, PGConnectionImpl connection) throws SQLException {
  if (val == null) {
    return null;
  }
  else if (val instanceof PGArray) {
    return coerceToArray(format, ((PGArray) val).getValue(), type, targetType, typeMap, connection);
  }
  else if (val.getClass().isArray()) {
    return coerceToArray(format, val, 0, Array.getLength(val), type, targetType, typeMap, connection);
  }

  throw createCoercionException(val.getClass(), targetType);
}

期望语句中的值是 PGArray 类型或实际数组;它无法将数组的字符串表示形式强制转换为数组的字符串表示形式。 :(

我正在尝试编写一个 jOOQ 转换器,它将在 String[] 之间进行转换和 PGArray ;理想情况下,这意味着 jOOQ 的 DefaultBindContext 将保留转换后的值足够好,然后 pgjdbc-ng 将能够正确处理它。

但是,我无法编写允许我执行此操作的 jOOQ 模式配置。我试过以下变体:

<customType>    
    <customType>
        <name>StringArray</name>
        <type>java.lang.String[]</type>
        <converter>my.package.PGStringArrayConverter</converter>
    </customType>
</customTypes>

<forcedTypes>
    <forcedType>
        <name>StringArray</name>
        <types>varchar\[\]</types>
    </forcedType>
</forcedTypes>

没有运气;生成的表对象引用 String[][] , 和 varchar[]与任何东西都不匹配。即使我将其分解,以便 forcedType 匹配任何类型但带有 <expression>只匹配我的专栏,转换器的类型是 java.lang.String ,我最终遇到了 Java 编译器提示无法将 Object[] 转换为 String[]。

这条隧道的尽头有曙光吗,还是我应该开始考虑迁移我的数据库?

最佳答案

所以,答案是“有点”。

我正在反向创建我的 PGStringArrayConverter 类;我创造了

public abstract class PGArrayConverter implements Converter<String[], PGArray>

最终起作用的是:

public abstract class PGArrayConverter implements Converter<Object, String[]> {
    @Override
    public String[] from(final Object databaseObject) {
        if (databaseObject == null) {
            return null;
        }
        if (databaseObject.getClass().isArray()) {
            return (String[]) databaseObject;
        }
        return (String[]) ((PGArray)databaseObject).getValue();
    }

    @Override
    public Object to(final String[] userObject) {
        if (userObject == null) {
            return null;
        }
        return new PGArray(null, null, userObject);
    }

    @Override
    public Class<Object> fromType() {
        return Object.class;
    }

    @Override
    public Class<String[]> toType() {
        return String[].class;
    }
}

from() 结果有点奇怪;我得到的是字符串数组,而不是 PGArray。我不认为数据库知道它“应该”将它们序列化为 PGArrays。

我还必须修改生成的代码,这有点令人讨厌。我的 schema.xml 文件包含:

<customType>
    <name>StringArray</name>
    <type>java.lang.String</type>
    <converter>my.package.PGStringArrayConverter</converter>
</customType>

<forcedType>
    <name>StringArray</name>
    <expression>.*tabular_answer_entry.text.*</expression>
    <types>.*</types>
</forcedType>

而且我必须更改生成的表文件以删除对 createField 数据类型的 .getArrayDataType() 调用:

public final org.jooq.TableField<my.package.gen.tables.records.TabularAnswerEntryRecord, java.lang.String[]> TEXT = createField("text", org.jooq.impl.DefaultDataType.getDefaultDataType("java.lang.String").getArrayDataType(), this, "", new my.package.PGStringArrayConverter());

到:

public final org.jooq.TableField<my.package.gen.tables.records.TabularAnswerEntryRecord, java.lang.String[]> TEXT = createField("text", org.jooq.impl.DefaultDataType.getDefaultDataType("java.lang.String"), this, "", new my.package.PGStringArrayConverter());

整个解决方案感觉有点老套,我将不得不编写一个单元测试的怪物来确保当我们更新任何相关包时它不会中断,但至少我能够读取和写入我的数据库。

关于java - 是否可以编写一个 jOOQ 转换器来应用于数组?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26724433/

相关文章:

sql - 如何使用 Postgres 中的 CSV 文件中的值更新选定的行?

java - 如何从 jOOQ 中的值 T 明确创建 Field<T> ?

java - JOOQ 在调用 select() 时创建高逗号

java - Reducer节点需要很长时间才能接收其记录

java - 从命令行编译 java 类时找不到符号错误

java - Spring - 将@Bean添加到没有名称属性的字符串

Java 线程垃圾是否收集

postgresql - 如果我对 PK 使用约束会怎样?

php - PostgreSQL:将 ARRAY[] 传递给 pg_query_params

java - 将条件列表传递给 JOOQ 中的 WHERE 子句