jooq - 从POJO

时间:2017-04-21 21:11:24

标签: java postgresql jooq

无论如何使用Jooq直接从POJO向PostgreSQL数据库插入一条新记录,该POJO扩展了一个具有id字段而不包含insert语句中id的一般标识类?

示例POJO:

@Data
public abstract class PersistenceIdentity {
    @Id
    @Column(name = "id", unique = true, nullable = false, precision = 7, insertable = false)
    private Integer id;

    @Column(name = "created_date")
    private LocalDateTime createdDate;

    public abstract Table<R> getJooqTable();
}

@Data
public class SocialNetwork extends PersistenceIdentity {

    @Column(name = "name")
    private String name;

    @Override
    public Table<SocialNetworkRecord> getJooqTable() {
        return Tables.SOCIAL_NETWORK;
    }

}

PostgreSQL架构是:

CREATE TABLE "social_network" (
    id              SERIAL NOT NULL PRIMARY KEY,
    created_date    TIMESTAMP DEFAULT now(),
    name            TEXT NOT NULL
);

我的代码要坚持POJO:

public <T extends PersistenceIdentity> T insertRecord(T record) {
    Record newRecord = db.newRecord(record.getJooqTable(), record);
    if (newRecord instanceof UpdatableRecord) {
        ((UpdatableRecord) newRecord).store();
    }

    return newRecord.into(record);
}

我意识到我可能正在做Jooq真正不适合的事情(即使用泛型类型),但是(看起来)工作得很好。

问题是,Jooq在insert语句中包含了id,然后我当然得到一个null值约束。我不想在它是新记录时插入它,但是我确实希望它在返回记录时(插入后),更新时以及select语句中包含它。

我不能简单地排除id,因为我稍后需要它来轻松解决一些@OneToMany / @ManyToOne限制。

我宁愿不必为每个POJO插入特定值(这就是我们用@Column注释的原因)。

Jooq是否不尊重@Column中的@Id或insertable = false参数?

任何人都可以对此有所了解吗?

编辑1 每个请求,下面是jOOQ生成的表对象的相关片段。我不确定这对于我正在尝试做的是否正确(即允许数据库生成ID),但我认为nextval('social_network_id_seq'::regclass)会实现这一点。

@Generated(
    value = {
        "http://www.jooq.org",
        "jOOQ version:3.9.1"
    },
    comments = "This class is generated by jOOQ"
)
@SuppressWarnings({ "all", "unchecked", "rawtypes" })
public class SocialNetwork extends TableImpl<SocialNetworkRecord> {

    /**
     * The column <code>public.social_network.id</code>.
     */
    public final TableField<SocialNetworkRecord, Integer> ID = createField("id", org.jooq.impl.SQLDataType.INTEGER.defaultValue(org.jooq.impl.DSL.field("nextval('social_network_id_seq'::regclass)", org.jooq.impl.SQLDataType.INTEGER)), this, "");

}

此外,我们使用mvn jooq-codegen:generate -Djooq.generator.name=org.jooq.util.XMLGenerator生成XML模式,然后从该XML配置生成jOOQ表对象。我们可以将XML配置推送到github,所有构建都可以简单地从中重新生成表对象。

这是XML:

<column>
    <table_catalog></table_catalog>
    <table_schema>public</table_schema>
    <table_name>social_network</table_name>
    <column_name>id</column_name>
    <data_type>integer</data_type>
    <character_maximum_length>0</character_maximum_length>
    <numeric_precision>32</numeric_precision>
    <numeric_scale>0</numeric_scale>
    <ordinal_position>1</ordinal_position>
    <column_default>nextval('social_network_id_seq'::regclass)</column_default>
</column>
<table_constraint>
    <constraint_catalog></constraint_catalog>
    <constraint_schema>public</constraint_schema>
    <constraint_name>social_network_pkey</constraint_name>
    <constraint_type>PRIMARY KEY</constraint_type>
    <table_catalog></table_catalog>
    <table_schema>public</table_schema>
    <table_name>social_network</table_name>
</table_constraint>
<table_constraint>
    <constraint_catalog></constraint_catalog>
    <constraint_schema>public</constraint_schema>
    <constraint_name>2200_17431_1_not_null</constraint_name>
    <constraint_type>CHECK</constraint_type>
    <table_catalog></table_catalog>
    <table_schema>public</table_schema>
    <table_name>social_network</table_name>
</table_constraint>
<table_constraint>
    <constraint_catalog></constraint_catalog>
    <constraint_schema>public</constraint_schema>
    <constraint_name>2200_17431_3_not_null</constraint_name>
    <constraint_type>CHECK</constraint_type>
    <table_catalog></table_catalog>
    <table_schema>public</table_schema>
    <table_name>social_network</table_name>
</table_constraint>
<key_column_usage>
    <column_name>id</column_name>
    <constraint_catalog></constraint_catalog>
    <constraint_schema>public</constraint_schema>
    <constraint_name>social_network_pkey</constraint_name>
    <ordinal_position>0</ordinal_position>
    <table_catalog></table_catalog>
    <table_schema>public</table_schema>
    <table_name>social_network</table_name>
</key_column_usage>

编辑2 我的SocialNetwork jOOQ生成的表对象没有getIdentity()方法,但是它确实有getPrimaryKey()方法,如果有帮助,我的SocialNetworkRecord类有两个构造函数:

public SocialNetworkRecord() {
    super(SocialNetwork.SOCIAL_NETWORK);
}

/**
 * Create a detached, initialised SocialNetworkRecord
 */
public SocialNetworkRecord(Integer id, Timestamp createdDate, String name) {
    super(SocialNetwork.SOCIAL_NETWORK);

    set(0, id);
    set(1, createdDate);
    set(2, name);
}

1 个答案:

答案 0 :(得分:1)

jOOQ的工作方式,有两个要素值得解释:

第1步:Record.from(Object)

Record newRecord = db.newRecord(record.getJooqTable(), record);

这个电话很方便:

Record newRecord = db.newRecord(record.getJooqTable());
newRecord.from(record);

Record.from(Object)会使用Record.set(Field, Object)record中的所有值复制到newRecord,再次设置记录的内部Record.changed(Field)标记。< / p>

第2步:UpdatableRecord.store()

您致电:

((UpdatableRecord) newRecord).store();

将对所执行的相关changed()INSERT语句考虑所有UPDATE个字段。这里的基本原理是人们有时想要明确地设置主键值,而不是让身份为它们生成值。即使主键上存在标识,有时也可能希望覆盖其值。因此,SQL标准数据库(例如Oracle 12c)支持两种指定标识的方式:

-- This can be overridden
GENERATED BY DEFAULT AS IDENTITY

-- This can never be overridden
GENERATED ALWAYS AS IDENTITY

(MySQL的AUTO_INCREMENT或PostgreSQL的SERIAL类型以相同的方式工作)

jOOQ在这里假设GENERATED BY DEFAULT AS IDENTITY。上述行为的唯一例外是当标识列为NOT NULL且标识的Record值为null且jOOQ的元模型同时知道两者时:

- `NOT NULL` constraint
- `GENERATED BY DEFAULT AS IDENTITY`

然后,jOOQ将省略考虑插入/更新的标识值。

3.9.2及更低版本中的错误:

请注意,在jOOQ版本3.9.2之前,XMLGenerator中存在一个错误/缺失功能,该功能会生成您要导入的XML文件:https://github.com/jOOQ/jOOQ/issues/6141。此错误导致不生成身份信息。

解决方法1:如果您无法影响jOOQ元模型

如果出于某种原因,您无法让jOOQ元模型反映您的NOT NULL约束和DEFAULT条款,那么您可以通过在您的身份之后重置身份的值来解决此限制Record.from(Object)使用Record.reset(Field)致电:

Record newRecord = db.newRecord(record.getJooqTable(), record);
newRecord.reset(identityColumn);
((UpdatableRecord) newRecord).store();

解决方法2:生成合成标识

代码生成器具有生成synthetic identities的功能。例如,如果您的所有标识列都被称为ID,则可以写下:

<!-- fully qualified -->
<syntheticIdentities>.*?\.ID</syntheticIdentities>

或者这个:

<!-- unqualified -->
<syntheticIdentities>ID</syntheticIdentities>