【发布时间】:2018-02-18 15:35:01
【问题描述】:
我正在使用 jOOQ 将很多行插入到一个多对多关系的表中。代码有效,生成的 SQL 符合预期,我的问题是我希望 jOOQ 代码可以更简单。
我有一个简化的结构(所有内容都被重命名,大部分字段被移除,大部分约束被移除,这只是一个愚蠢但准确的结构示例):
CREATE TABLE person (
person_id BIGSERIAL PRIMARY KEY,
person_name VARCHAR(64) NOT NULL UNIQUE
);
CREATE TABLE company (
company_id BIGSERIAL PRIMARY KEY,
company_name VARCHAR(100) NOT NULL UNIQUE
);
CREATE TABLE employment_contract (
company_id BIGINT NOT NULL REFERENCES company,
person_id BIGINT NOT NULL REFERENCES person,
PRIMARY KEY (company_id, person_id),
salary INT NOT NULL,
creation_date_time TIMESTAMP NOT NULL
);
我的插入代码:
Table<Record4<String, String, Integer, Timestamp>> insertValues = values(
row(
cast(null, COMPANY.COMPANY_NAME),
cast(null, PERSON.PERSON_NAME),
cast(null, EMPLOYMENT_CONTRACT.SALARY),
cast(null, EMPLOYMENT_CONTRACT.CREATION_DATE_TIME)
)
).as("insert_values",
COMPANY.COMPANY_NAME.getName(), -- these lines are bugging me
PERSON.PERSON_NAME.getName(),
EMPLOYMENT_CONTRACT.SALARY.getName(),
EMPLOYMENT_CONTRACT.CREATION_DATE_TIME.getName()
);
Insert<AffectedSubscriberRecord> insert = insertInto(EMPLOYMENT_CONTRACT)
.columns(EMPLOYMENT_CONTRACT.COMPANY_ID,
EMPLOYMENT_CONTRACT.PERSON_ID,
EMPLOYMENT_CONTRACT.SALARY,
EMPLOYMENT_CONTRACT.CREATION_DATE_TIME
)
.select(
select(
COMPANY.COMPANY_ID,
PERSON.PERSON_ID,
insertValues.field(EMPLOYMENT_CONTRACT.SALARY),
insertValues.field(EMPLOYMENT_CONTRACT.CREATION_DATE_TIME)
)
.from(insertValues)
.join(COMPANY).using(COMPANY.COMPANY_NAME)
.join(PERSON).using(PERSON.PERSON_NAME)
);
然后我将所有行绑定到context.batch(insert) 并执行该操作。我确定person 和company 的引用键已经存在,并且原始代码也解决了重复,我们这里不需要关心这些东西。
让我烦恼的是insertValues 表 - 我需要在容易出错的复制粘贴中指定列类型和名称两次,使用 .getName() 调用会掩盖整个代码并且很容易错误地交换.我尝试的是:
Table<Record4<String, String, Integer, Timestamp>> insertValues = values(
row( (String)null, (String)null, (Integer)null, (Timestamp)null )
).as("insert_values",
COMPANY.COMPANY_NAME.getName(),
PERSON.PERSON_NAME.getName(),
EMPLOYMENT_CONTRACT.SALARY.getName(),
EMPLOYMENT_CONTRACT.CREATION_DATE_TIME.getName()
);
这显然不起作用,jOOQ 和 Postgres 都不知道插入的类型,DB 猜测 varchar 并失败。我们需要 jOOQ 至少为查询中的第一行生成类型转换。再试一次:
Table<Record4<String, String, Integer, Timestamp>> insertValues = values(
row( COMPANY.COMPANY_NAME, PERSON.PERSON_NAME, EMPLOYMENT_CONTRACT.SALARY, EMPLOYMENT_CONTRACT.CREATION_DATE_TIME )
).as("insert_values");
这将是炸弹。 JOOQ 以这种方式知道正确的类型,并且可以为我生成强制转换,所有代码重复都消失了,一切都安全了。然而,这也失败了。 JOOQ 不明白我给了它一排空值。
有没有什么方法可以在没有不干净的.getName() 调用的情况下实现相同(或等效)的结果查询,直接在某处传递字段?
【问题讨论】:
-
我认为这个问题已经在这篇文章stackoverflow.com/questions/10264001/… 中讨论过了
-
@mohamedchaawa 这确实是一个类似的问题。不过,在这种情况下,我想将一些现有列别名到一个新表中。目前似乎不可能,我会向 jooq 提出罚单。
-
我认为插入 NULL 是模式设计的代码异味。它迫使您始终进行防御性地检查 null 的编程,这会使您的代码难以遵循。我想你这样做只是为了举例,但我想我会提到它。
-
@Stuporman 我这样做是为了批量插入绑定,jooq.org/doc/3.10/manual/sql-execution/batch-execution。
-
P.S.而不是
cast(null, COMPANY.COMPANY_NAME),我们一直在使用param(COMPANY.COMPANY_NAME)。但其余的保持不变。
标签: java sql postgresql jooq