Читать в оригинале

<< Предыдущая Оглавление Следующая >>


4.3.4 Триггер, обеспечивающий ссылочную целостность

Согласно рис. 1.1, таблица WORK рассматриваемого в пособии примера имеет обязательного потомка в таблице TRANSACTION. Это означает, что всякий раз когда в таблицу WORK вставляется строка, необходимо вставить соответствующую ей строку в таблицу TRANSACTION.

Реализовать такие ограничения ссылочной целостности непросто. Пер­вое, что приходит в голову, — это создать завершающий триггер для таб­лицы WORK, который бы проверял, что приложение создало требуемую строку в таблице TRANSACTION. Однако любой такой триггер будет за­пускаться непосредственно после вставки строки в таблицу WORK, то есть до того как приложение получит шанс вставить новую строку в таблицу TRANSACTION. Таким образом, триггер не сможет увидеть строку, ко­торую собирается вставить приложение.

Другое решение — потребовать от приложения создать строку в таб­лице TRANSACTION перед тем, как вставить новую строку в таблицу WORK. Но в этом случае мы переопределяем связь так, что теперь стро­ка в таблице TRANSACTION требует строки в таблице WORK. Поэтому СУБД откажется вставлять в таблицу TRANSACTION строку, не имею­щую родителя, и сделает она это еще до того, как будет вызван какой-либо триггер таблицы TRANSACTION. Таким образом, триггер, определенный для таблицы TRANSACTION, никогда не получит возможности создать требуемую строку в таблице WORK.

Одно возможное, хотя и не очень красивое, решение заключается в том, чтобы создать пару триггеров. Первый из них будет создавать строку в таблице TRANSACTION при вставке строки в таблицу WORK. Второй триггер будет удалять строку, вставленную по умолчанию, когда прило­жение захочет вставить строку в таблицу TRANSACTION. При таком под­ходе, если приложение не создаст требуемой строки, будет использоваться строка, вставленная триггером. Если приложение создаст новую строку в таблице TRANSACTION, то вставленная по умолчанию строка будет предварительно удалена.

Эта пара триггеров представлена в листингах 4.4 и 4.5. Триггер, изображенный в листинге 4.4, создает строку по умолчанию в табли­це TRANSACTION. Сначала он проверяет, нет ли в этой таблице суще­ствующей строки с таким WorkID; если нет, он вставляет новую строку. Второй триггер (листинг 4.5) удаляет строку, созданную первым триг­гером, когда пользователь вставляет соответствующую строку в таблицу TRANSACTION.

Листинг 4.4.

CREATE OR REPLACE TRIGGER EnforceTransChild AFTER INSERT ON WORK
FOR EACH ROW
DECLARE
RowCount int; NewID int; BEGIN
NewID := :new.WorkID; SELECT Count(*) INTO RowCount FROM TRANSACTION WHERE WorkID = NewID
AND CustomerlD IS NULL; IF RowCount = 0 THEN
INSERT INTO TRANSACTION (TransactionID, DateAcquired, WorkID) VALUES (TransID.NextVal, SysDate, NewID);
END IF;
END;
/

Листинг 4.5.

CREATE OR REPLACE TRIGGER RemoveDupTrans BEFORE INSERT ON TRANSACTION
FOR EACH ROW
BEGIN
DELETE FROM TRANSACTION WHERE WorkID = :new.WorkID AND CustomerlD IS NULL
AND TransactionID <> :new.TransactionID;
END;
/

Тем не менее это решение нельзя назвать удовлетворительным. Еще од­на альтернатива, более сложная в реализации, но эстетически более при­влекательная, — потребовать от приложения, чтобы новые произведения добавлялись в базу данных через представление, содержащее все необходи­мые данные для таблицы WORK и TRANSACTION. В этом случае встав­ку данных из представления WORK/TRANSACTION в таблицы WORK и TRANSACTION осуществлял бы триггер, а прямую вставку строк в эти таблицы следовало бы запретить.

 



<< Предыдущая Оглавление Следующая >>