当前位置: 首页 > 知识库问答 >
问题:

jOOQ转换器在写入记录时隐式设置值

赵镜
2023-03-14

在我的postgresql数据库的一个表中,有2列具有默认值。

我在jOOQ生成器配置中为其中一个定义了一个转换器。

当我执行函数record.store()时,默认值很好地用于没有转换器的字段,但不用于另一个变为null的字段。

我从来没有明确设置这些字段,但我猜record.changed(MY_OBJECT. FIELD)==true后执行的转换器。

我不确定这是否是预期的行为。是虫子吗?有解决方法吗?

编辑:这是使用的代码

TimestampBinding.java

public class TimestampBinding implements Binding<Timestamp, Instant> {

    private static final Converter<Timestamp, Instant> converter = new TimestampConverter();

    private final DefaultBinding<Timestamp, Instant> delegate = new DefaultBinding<> (converter());

    @Override
    public Converter<Timestamp, Instant> converter() { return converter; }

    @Override
    public void sql(BindingSQLContext<Instant> ctx) throws SQLException {
        delegate.sql(ctx);
    }

    @Override
    public void register(BindingRegisterContext<Instant> ctx) throws SQLException {
        delegate.register(ctx);
    }

    @Override
    public void set(BindingSetStatementContext<Instant> ctx) throws SQLException {
        delegate.set(ctx);
    }

    @Override
    public void set(BindingSetSQLOutputContext<Instant> ctx) throws SQLException {
        delegate.set(ctx);
    }

    @Override
    public void get(BindingGetResultSetContext<Instant> ctx) throws SQLException {
        delegate.get(ctx);
    }

    @Override
    public void get(BindingGetStatementContext<Instant> ctx) throws SQLException {
        delegate.get(ctx);
    }

    @Override
    public void get(BindingGetSQLInputContext<Instant> ctx) throws SQLException {
        delegate.get(ctx);
    }
}

TimestampConverter.java

public class TimestampConverter implements Converter<Timestamp, Instant> {
    @Override
    public Instant from(Timestamp ts) {
        return ts == null ? null : ts.toInstant();
    }
    @Override
    public Timestamp to(Instant instant) {
        return instant == null ? null : Timestamp.from(instant);
    }
    @Override
    public Class<Timestamp> fromType() { return Timestamp.class; }
    @Override
    public Class<Instant> toType() { return Instant.class; }
}

sql

CREATE TABLE user (
  id uuid PRIMARY KEY,
  active boolean NOT NULL DEFAULT false,
  created_at timestamptz DEFAULT now()
);

存储记录

user.setId(UUID.randomUUID());
UserRecord userRecord = DSL.using(conn, SQLDialect.POSTGRES_9_3)
                .newRecord(userTable.USER, user);
userRecord.store();

共有1个答案

左丘峰
2023-03-14

这种行为是“预期的”,在jOOQ有着悠久的历史。简要说明如下:

  • 您的列activeNot NULL,因此Java值null被解释为SQL值DEFAULT,无论Record.changed()标志如何。
  • 您的列created_at为空,因此Java值null被解释
    • 作为SQL值DEFAULTifRecord.changed(CREATED_AT)==false
    • 作为SQL值NULL如果Record.changed(CREATED_AT)==true

    通过调用DSLContext。newRecord(),您正在将用户POJO中的所有值复制到用户记录中,包括所有空值。jOOQ无法区分未斜体的值和显式的值。

    在您的特定情况下,最好的解决方案是将所有列声明为非空(无论如何,在概念层面上更好):

    CREATE TABLE user (
      id uuid PRIMARY KEY,
      active boolean NOT NULL DEFAULT false,
      created_at timestamptz NOT NULL DEFAULT now()
    );
    

 类似资料:
  • 我有一个简单的方法(使用jooq),基本上是这样做的: 在表'MY_OBJECT'中,我有一个字段'id',其定义为: 每当我运行上面提到的代码时,都会出现错误: 在我看来,问题是jOOq试图将值写入标识列。MyConvertor将其保留为null的原因是,该值将由db生成。如何使jooq不尝试向该字段写入null?

  • 在我的Oracle数据库中,我有存储为VARCHAR的数量值。从数据库中检索记录时,我希望将它们映射到一个POJO,其中金额值表示为double。不幸的是,我不能使用强制类型,因为在数据库中,所有内容都存储为VARCHAR,并且没有模式将列标识为包含金额值的列。 我正在查看jOOQ转换器,这似乎是我想要的。因此,我为此创建了一个jOOQ转换器: 然而,每当我想使用将数据库记录映射到我的POJO时,

  • 目前我正在从pojos列表映射到记录,我希望能够一次插入多行。我如何在JOOQ中用一个事务做到这一点? 我曾尝试将列表放入“值”中,但出现异常“值的数量必须与字段的数量匹配”

  • 我有两个表,asdf和qwer,两个表都有一个名为“id”的主键。当我连接这两个表时,结果将有两个名为id的列,而JOOQ无法将记录正确映射到pojo。 现在,每个Asdf实例都与元组中对应的Qwer实例具有相同的id。 有没有聪明的别名技巧可以解决这个问题,或者我在JOOQ文档中遗漏了什么,或者这是JOOQ中的一个bug?

  • JavaScript 是非常宽容的,「来者不拒」,不在乎什么类型。 例如,它如果想要接受数字,它并不拒绝其他类型的值,而是试图把它们转换成数字: > '5' - '2' 3 > '5' * '2' 10 自动转换为布尔值通常不会引起问题,而且往往很有用(译注:比如在C语言里,根本就没有布尔类型。 即使如此,这些隐式转换也会引起怪癖(quirks)。 但是当自动转换为字符串时,可能会引起问题。 一

  • 我在页面加载上有一些问题,因为页面加载了一些异步的东西,我想中断页面加载来继续我测试的下一个步骤。 我该怎么解决这个?