无论如何使用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);
}
答案 0 :(得分:1)
jOOQ的工作方式,有两个要素值得解释:
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>
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将省略考虑插入/更新的标识值。
请注意,在jOOQ版本3.9.2之前,XMLGenerator
中存在一个错误/缺失功能,该功能会生成您要导入的XML文件:https://github.com/jOOQ/jOOQ/issues/6141。此错误导致不生成身份信息。
如果出于某种原因,您无法让jOOQ元模型反映您的NOT NULL
约束和DEFAULT
条款,那么您可以通过在您的身份之后重置身份的值来解决此限制Record.from(Object)
使用Record.reset(Field)
致电:
Record newRecord = db.newRecord(record.getJooqTable(), record);
newRecord.reset(identityColumn);
((UpdatableRecord) newRecord).store();
代码生成器具有生成synthetic identities的功能。例如,如果您的所有标识列都被称为ID
,则可以写下:
<!-- fully qualified -->
<syntheticIdentities>.*?\.ID</syntheticIdentities>
或者这个:
<!-- unqualified -->
<syntheticIdentities>ID</syntheticIdentities>