使用 SelectWhereStep 构建动态查询时未调用 JOOQ 自定义数据类型转换器

问题描述 投票:0回答:1

我有一个用于 Oracle DB 中布尔值的自定义数据类型转换器:

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>
      <objectType>ALL</objectType>
      <converter>com.jooq.config.CustomBooleanConverter</converter>                                                    <includeExpression>.*\.AMENDABLE</includeExpression>
      <includeTypes>.*</includeTypes>
 </forcedType>

JOOQ 生成的文件看起来不错:

    /**
     * The column <code>TABLEXX.AMENDABLE</code>.
     */
    public final TableField<TableXXRecord, Boolean> AMENDABLE = createField(DSL.name("AMENDABLE"), SQLDataType.VARCHAR(6), this, "", new CustomBooleanConverter());

但是,当使用 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 代码如下所示:

SelectWhereStep<?> query = selectFrom(subquery.asTable);
query.where(getFilteringCondition(specs, class, table, dsl, resource)); 

此 getFilteringCondition 函数返回一个带有布尔字段、值为 true 和比较器为“equal”的 Condition 对象。 在包装子查询的查询中添加条件 我进行了调试,并且从未调用 CustomBooleanConverter 类,并且我尝试使用强制类型配置的不同可选参数,但到目前为止没有成功。

知道我做错了什么吗?

我期望 JOOQ 在根据所实现的配置将列命名为“AMENDABLE”时使用布尔类型的自定义转换器。但 JOOQ 使用默认的布尔值到整数的布尔转换 (true = 1),并且我期望将布尔值转换为字符串,例如 (true = "true")。

这使得 sql 执行在运行时失败,因为列是 VARCHARD 但 JOOQ 使用 NUMBER 值

java oracle jooq sqldatatypes
1个回答
0
投票

我也遇到了类似的问题。

jOOQ 查询条件和强制类型转换器

虽然我不一定能解释 jOOQ 内部的技术方面,但似乎带有转换器的简单强制类型对于读取和写入值来说效果很好,但是要在 WHERE 子句中使用转换后的值,您需要使用绑定而不是简单的转换器。

https://www.jooq.org/doc/latest/manual/code- Generation/codegen-advanced/codegen-config-database/codegen-database-forced-types/codegen-database-forced-types-binding/

<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()
方法即可提供适当的转换器。

© www.soinside.com 2019 - 2024. All rights reserved.