jOOQ转换器在写入记录时隐式设置一个值
jOOQ converter implicitly set a value when writing a record
在我的 postgresql 数据库的 table 中,我有 2 个具有默认值的列。
我在 jOOQ 生成器配置中为其中之一定义了一个转换器。
当我执行函数 record.store() 时,默认值适用于没有转换器的字段,但不适用于另一个变为空的字段。
我从未明确设置这些字段,但我猜想 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();
这种行为是 "expected" 并且在 jOOQ 中有很长的历史。简短的解释在这里:
- 您的列
active
是 NOT NULL
,因此 Java 值 null
被解释为 SQL 值 DEFAULT
,无论Record.changed()
标志。
- 您的列
created_at
可以为空,因此 Java 值 null
被解释
- 作为 SQL 值
DEFAULT
if Record.changed(CREATED_AT) == false
- 作为 SQL 值
NULL
if 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()
);
在我的 postgresql 数据库的 table 中,我有 2 个具有默认值的列。
我在 jOOQ 生成器配置中为其中之一定义了一个转换器。
当我执行函数 record.store() 时,默认值适用于没有转换器的字段,但不适用于另一个变为空的字段。
我从未明确设置这些字段,但我猜想 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();
这种行为是 "expected" 并且在 jOOQ 中有很长的历史。简短的解释在这里:
- 您的列
active
是NOT NULL
,因此 Java 值null
被解释为 SQL 值DEFAULT
,无论Record.changed()
标志。 - 您的列
created_at
可以为空,因此 Java 值null
被解释- 作为 SQL 值
DEFAULT
ifRecord.changed(CREATED_AT) == false
- 作为 SQL 值
NULL
ifRecord.changed(CREATED_AT) == true
- 作为 SQL 值
通过调用 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()
);