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 Листинг 4.5. CREATE OR REPLACE TRIGGER RemoveDupTrans BEFORE INSERT ON TRANSACTION Тем не менее это решение нельзя назвать удовлетворительным. Еще одна альтернатива, более сложная в реализации, но эстетически более привлекательная, — потребовать от приложения, чтобы новые произведения добавлялись в базу данных через представление, содержащее все необходимые данные для таблицы WORK и TRANSACTION. В этом случае вставку данных из представления WORK/TRANSACTION в таблицы WORK и TRANSACTION осуществлял бы триггер, а прямую вставку строк в эти таблицы следовало бы запретить.
|