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

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

我有一个用于 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 值

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.