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

时间:2016-04-20 09:24:55

标签: java sql jooq

在我的postgresql数据库的表中,我有两列默认值。

我在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 个答案:

答案 0 :(得分:0)

这种行为是“预期的”,在jOOQ中有很长的历史。简短的解释如下:

  • 您的列activeNOT NULL,因此无论null标志如何,Java值DEFAULT都被解释为SQL值Record.changed()。< / LI>
  • 您的列created_at可以为空,因此会解释Java值null
    • 作为DEFAULT
    • 的SQL值Record.changed(CREATED_AT) == false
    • 作为NULL
    • 的SQL值Record.changed(CREATED_AT) == true

当您致电DSLContext.newRecord()时,您正在将user POJO中的所有值复制到userRecord,包括所有null值。 jOOQ无法区分未经初始化的null值和明确显示的null值... null

在您的特定情况下,最佳解决方案是声明所有列NOT NULL(无论如何在概念级别上更好):

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