我有一个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类型或实际数组;它无法将数组的String表示强制转换为数组的String表示形式。 :(
我正在尝试编写一个将在String[]
和PGArray
之间转换的jOOQ转换器;理想情况下,这意味着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 []。
此隧道的末尾是否有任何亮点,或者我应该开始寻找迁移我的数据库吗?
答案 0 :(得分:1)
所以,事实证明答案是,“有点儿。”
我向后创建了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()
结果有些奇怪;我得到的是字符串数组,而不是PGArrays。我不认为数据库知道它“应该”将它们序列化为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());
整个解决方案感觉有点hacky,我将不得不写一个单元测试的怪物,以确保当我们更新任何相关的包时不会破坏,但至少我能够读取和写入我的数据库。