Я использую 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()
, непосредственно передавая поля где-нибудь?