我正在尝试使用 jOOQ 3.4.2 中的 UpdatableRecords 插入新记录。该模式非常简洁且易于使用,除了 INSERT
将 null 值读取为无值并忽略默认值或生成的索引。我如何使用 UpdatableRecord 执行符合默认值和生成索引的插入?
这是我的 table :
CREATE TABLE aragorn_sys.org_person (
org_person_id SERIAL NOT NULL,
first_name CHARACTER VARYING(128) NOT NULL,
last_name CHARACTER VARYING(128) NOT NULL,
created_time TIMESTAMP WITH TIME ZONE DEFAULT current_timestamp NOT NULL,
created_by_user_id INTEGER,
last_modified_time TIMESTAMP WITH TIME ZONE,
last_modified_by_user_id INTEGER,
org_id INTEGER NOT NULL,
CONSTRAINT PK_org_person PRIMARY KEY (org_person_id)
);
记下我的主键和默认值。现在这是我的 jOOQ 代码:
// orgPerson represents a POJO filled with my values to be inserted and null for everything else
// Note that orgPerson.orgPersonId is null
OrgPersonRecord orgPersonRecord = create.newRecord( ORG_PERSON, orgPerson );
Integer orgPersonId = create.executeInsert( orgPersonRecord );
但是当我运行它时,我得到错误 null value in column "org_person_id"violates not-null constraint
。
我注意到 jOOQ 文档说调用 newRecord
会自动将 UpdatableRecord 上的所有内部“已更改”标志设置为 true。然后我尝试了这个:
// orgPerson represents a POJO filled with my values to be inserted and null for everything else
// Note that orgPerson.orgPersonId is null
OrgPersonRecord orgPersonRecord = create.newRecord( ORG_PERSON, orgPerson );
orgPersonRecord.changed( ORG_PERSON.ORG_PERSON_ID, false );
orgPersonRecord.changed( ORG_PERSON.CREATED_TIME, false );
orgPersonRecord.insert()
Integer orgPersonId = orgPersonRecord.getOrgPersonId();
但这给了我错误 ERROR: duplicate key value violates unique constraint "pk_org_person"
。当我重复执行此操作时,值似乎一直增加 1。这对我来说真的没有意义,但我更大的问题是:是否有一种好方法可以根据我的对象值执行 INSERT ,或者更好的是,只包含非空列?
我看到了JOOQ ignoring database columns with default values ,但这似乎并不能解决这个问题。关于处理此问题的最简洁方法的任何建议?
顺便说一句,到目前为止,与 jOOQ 的合作非常棒。 Lukas,谢谢你提供这个很棒的工具!
更新 #1:
Lukas 在下面的回答中解决了“not null 问题”,这很容易解决。
对于重复的主键,我绝对不会混淆 INSERT
和 UPDATE
。当我运行上面的代码时(自原始帖子以来略有更新),jOOQ 似乎任意选择 OrgPersonId
的“起始”主键值。例如,当我第一次加载我的环境时,对于 OrgPersonId
,jOOQ 可能以“11”开头。
然后,当我执行 INSERT
时,jOOQ 将尝试为 OrgPersonId
提供值“11”,我将得到 ERROR: duplicate键值
和 INSERT
将失败。如果我然后重复 INSERT
,jOOQ 使用“12”,然后是“13”。它的成功或失败取决于该 ID 是否可用,但它不是以正确的 ID“开始”。
手册 ( http://www.jooq.org/doc/3.4/manual/sql-execution/crud-with-updatablerecords/identity-values/ ) 说 如果您使用 jOOQ 的代码生成器,上表将生成一个带有 IDENTITY 列的 org.jooq.UpdatableRecord。 jOOQ 在内部使用此信息,在调用 store() 后更新 ID
。
更新 #2:
好的,我刚刚在 Postgres 中直接尝试了生成的查询,但它也失败了,并出现了同样的问题。所以,很明显这是一个 Postgres 问题而不是 jOOQ 问题。当我找到它时,我会发布最终解决方案,以防其他人遇到这个问题。
更新 #3:
问题已解决。我们使用 FlywayDB(另一个很棒的工具)来自动化我们的数据库模式迁移,并且我们在我们的 Flyway 脚本中有一堆 INSERT
语句手动插入 ID 号。这很方便,因为我们想创建一堆虚拟数据并想保证正确的外键关系。
但是手动指定主键增量不会推进 Postgres 序列!因此,我们必须在(正确操作)jOOQ 获得正确的序列值之前循环遍历 Postgres 序列。
解决方案是删除我们在演示数据迁移脚本中手动插入的所有主键。
最佳答案
违反非空约束
您描述的第一部分是一个缺陷 ( #3582 ),它与之前的问题 ( #2700 ) 有关,它强制将从 POJO 加载的 null
值存储到 jOOQ 中Records
用于 NOT NULL
的数据库列。修复将在 jOOQ 3.5.0、3.4.3、3.3.4 和 3.2.7 中
重复键值违反唯一约束“pk_org_person”
第二部分可能是由于您实际上是在加载现有记录然后调用 executeInsert()
造成的。在它上面(观察 INSERT
,它将始终执行 INSERT
语句)。您可能想调用 executeUpdate()
, 而不是
关于java - 插入新的 UpdatableRecord 并在重复的主键上接收错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25399183/