Вы можете применить это на чистом уровне базы данных, добавив внешний ключ в таблицу book
, который указывает на тег (любой тег) в таблице book_tag
. На данный момент ваша модель базы данных выглядит следующим образом:
create table book (
id int primary key not null,
title varchar(50)
);
create table tag (
id int primary key not null,
name varchar(50)
);
create table book_tag (
book_id int not null,
book_tag int not null,
primary key (book_id, book_tag)
);
Теперь добавьте дополнительный внешний ключ, который указывает на тег:
alter table book add column a_tag int not null;
alter table book add constraint fk1 foreign key (id, a_tag)
references book_tag (book_id, tag_id) deferrable initially deferred;
Теперь, когда вы вставляете книгу, она может временно не иметь тега, но только когда транзакция еще не завершена. Вам нужно вставить тег перед фиксацией. Если вы этого не сделаете, ограничение не будет выполнено, транзакция будет отменена, и вставка не произойдет.
Примечание : обратите внимание, что для этого требуется использование отложенных ограничений (см. deferrable initially deferred
), что является частью SQL стандарта , но редко применяется. К счастью, PostgreSQL делает.
РЕДАКТИРОВАТЬ - Добавление примера
Учитывая предыдущие измененные таблицы, вы можете попробовать вставить книгу без тегов (не получится) и с тегами (последовательно), как показано ниже:
insert into tag (id, name) values (10, 'classic');
insert into tag (id, name) values (12, 'action');
insert into tag (id, name) values (13, 'science fiction');
-- begin transaction
insert into book (id, title, a_tag) values (1, 'Moby Dick', 123);
commit; -- fails
-- begin transaction
insert into book (id, title, a_tag) values (2, 'Frankenstein', 456);
insert into book_tag (book_id, book_tag) values (2, 10);
insert into book_tag (book_id, book_tag) values (2, 13);
update book set a_tag = 10;
commit; -- succeeds