我有一个用于 java 布尔字段的自定义数据类型转换器,它将与 Oracle 中的 VARCHAR2 (6) 列匹配,并存储在数据库文本“false”或“true”
public class CustomBooleanConverter implements Converter<String, Boolean>{
@Override
public Boolean from(String s) {
if (s == null) {
return null;
}
return s.equals("true");
}
@Override
public String to(Boolean aBoolean) {
if (aBoolean == null) {
return null;
}
return aBoolean.booleanValue() ? "true" : "false";
}
@Override
public Class<String> fromType() {
return String.class;
}
@Override
public Class<Boolean> toType() {
return Boolean.class;
}
}
并声明在 maven 配置中使用,如下所示:
<forcedType>
<userType>java.lang.Boolean</userType>
<binding>com.jooq.config.CustomBooleanBinding</binding>
<includeExpression>.*\.AMENDABLE</includeExpression>
</forcedType>
这将是自定义绑定类:
public class CustomBooleanBinding implements Binding<String, Boolean> {
@Override
public Converter<String, Boolean> converter() {
return new CustomBooleanConverter ();
}
@Override
public void sql(BindingSQLContext<Boolean> bindingSQLContext) throws SQLException {
String converted = converter().to(bindingSQLContext.value());
if (bindingSQLContext.render().paramType() == ParamType.INLINED){
if (converted == null) {
bindingSQLContext.render().sql("NULL");
} else {
bindingSQLContext.render().sql(converted);
}
} else {
bindingSQLContext.render().sql(bindingSQLContext.variable());
}
}
@Override
public void register(BindingRegisterContext<Boolean> bindingRegisterContext) throws SQLException {
throw new SQLFeatureNotSupportedException();
}
@Override
public void set(BindingSetStatementContext<Boolean> bindingSetStatementContext) throws SQLException {
String value = bindingSetStatementContext.convert(converter()).value();
bindingSetStatementContext.statement().setString(bindingSetStatementContext.index(),
value == null ? null : value);
}
@Override
public void set(BindingSetSQLOutputContext<Boolean> bindingSetSQLOutputContext) throws SQLException {
throw new SQLFeatureNotSupportedException();
}
@Override
public void get(BindingGetResultSetContext<Boolean> bindingGetResultSetContext) throws SQLException {
bindingGetResultSetContext.convert(converter());
}
@Override
public void get(BindingGetStatementContext<Boolean> bindingGetStatementContext) throws SQLException {
bindingGetStatementContext.convert(converter());
}
@Override
public void get(BindingGetSQLInputContext<Boolean> bindingGetSQLInputContext) throws SQLException {
throw new SQLFeatureNotSupportedException();
}
}
JOOQ 生成的文件看起来不错:
/**
* The column <code>TABLEXX.AMENDABLE</code>.
*/
public final TableField<TableXXRecord, Boolean> AMENDABLE = createField(DSL.name("AMENDABLE"), SQLDataType.VARCHAR(6), this, "", new CustomBooleanBinding());
但是,当使用 SelectWhereStep 构建动态查询,并添加一个名为 AMENDABLE 且布尔类型且值为 true 的字段的条件时,呈现的 SQL 最终如下所示:
select alias_90892522.OTHER COLUMN,
......,
alias_90892522.AMENDABLE
from (
select OTHER COLUMN,
......,
AMENDABLE
from tableXX
) alias_90892522
where
(
"alias_90892522"."OTHER COLUMN" = '0005698'
and "alias_90892522"."AMENDABLE" = 1
)
Java 代码如下所示:
SelectConditionStep subquery= select(tableXX.Other_column,tableXX.amendable ).from(tableXX);
Table<?> table = subquery.asTable;
SelectWhereStep<?> query = selectFrom(table);
query.where(table.field("OTHER_COLUM", String.class).equal("0005698"))
query.where(table.field("AMENDABLE,Boolean.class).equal(true));
之所以这样做,是因为查询是基于表和列的注释动态构建的。 我调试了代码,但 CustomBooleanBinding 类从未被调用。
知道我做错了什么吗?
JOOQ版本为3.14.9
我希望 JOOQ 每当任何列根据所实现的配置被命名为“AMENDABLE”时,都会使用布尔类型的自定义绑定转换器。但 JOOQ 相反使用布尔值到整数的默认布尔转换(true = 1),并且我期望将布尔值转换为字符串(true =“true”)。
这使得 sql 执行在运行时失败,因为列是 VARCHARD 但 JOOQ 使用 NUMBER 值
我也遇到了类似的问题。
虽然我不一定能解释 jOOQ 内部的技术方面,但似乎带有转换器的简单强制类型对于读取和写入值来说效果很好,但是要在 WHERE 子句中使用转换后的值,您需要使用绑定而不是简单的转换器。
<forcedType>
<userType>com.example.MyDataType</userType>
<binding>com.exampe.MyDataTypeBinding</binding>
<includeExpression>
my_table\.my_column
</includeExpression>
</forcedType>
绑定实现可以利用现有的转换器,但您需要做一些额外的工作来为您的数据类型呈现适当的 SQL。
就我而言,我编写了一个抽象绑定实现,使用 SMALLINT 列来表示枚举。
abstract class AbstractSmallintEnumBinding<T> implements Binding<Short, T> {
@Override
public void sql(BindingSQLContext<T> ctx) throws SQLException {
Short converted = converter().to(ctx.value());
if (ctx.render().paramType() == ParamType.INLINED) {
if (converted == null) {
ctx.render().sql("NULL");
} else {
ctx.render().sql(String.valueOf(converted));
}
} else {
ctx.render().sql(ctx.variable());
}
}
@Override
public void register(BindingRegisterContext<T> ctx) throws SQLException {
ctx.statement().registerOutParameter(ctx.index(), Types.SMALLINT);
}
@Override
public void set(BindingSetStatementContext<T> ctx) throws SQLException {
Short value = converter().to(ctx.value());
if (value == null) {
ctx.statement().setNull(ctx.index(), Types.SMALLINT);
} else {
ctx.statement().setInt(ctx.index(), value);
}
}
@Override
public void set(BindingSetSQLOutputContext<T> ctx) throws SQLException {
throw new SQLFeatureNotSupportedException();
}
@Override
public void get(BindingGetResultSetContext<T> ctx) throws SQLException {
Short value = ctx.resultSet().getShort(ctx.index());
if (ctx.resultSet().wasNull()) {
value = null;
}
ctx.value(converter().from(value));
}
@Override
public void get(BindingGetStatementContext<T> ctx) throws SQLException {
ctx.value(converter().from(ctx.statement().getShort(ctx.index())));
}
@Override
public void get(BindingGetSQLInputContext<T> ctx) throws SQLException {
throw new SQLFeatureNotSupportedException();
}
}
子类只需使用
extends AbstractSmallintEnumBinding<MyEnumType>
并实现 conveter()
方法即可提供适当的转换器。