Как известно разработчикам на Oracle Forms в триггере WHEN-VALIDATE-ITEM нельзя выполнить переход на другой блок командой GO_BLOCK. Если это сделать, мы получим исключение FRM-40737: Illegal restricted procedure GO_BLOCK in WHEN-VALIDATE-ITEM trigger. Это очень неприятное ограничение Oracle Forms не позволяет выполнять некоторые сценарии при вводе данных. В этой статье приводится способ обойти это ограничение.
Например, у вас есть форма, в которой два блока данных. Второй блок данных является подчиненным первому. Допустим, в родительском блоке данных есть числовое поле, в результате изменения значения которого пересчитываются некоторые значения в таблице подчиненного блока. По логике работы формы после ввода числового значения в родительском блоке надо обновить дочерний блок. Обычно это выполняется командами
GO_BLOCK('child_block_name');
EXECUTE_QUERY;
Но выполнить эти команды после ввода значения числового поля в родительском блоке данных не удастся, так как действия по обновлению дочерней таблицы мы выполняем в триггере WHEN-VALIDATE-ITEM и если выполнить там же команду GO_BLOCK, мы получим FRM-40737: Illegal restricted procedure GO_BLOCK in WHEN-VALIDATE-ITEM trigger.
Что делать в этом случае? Подразумевать, что пользователь сам обновит данные дочернего блока? Или сообщить ему об этом, чтобы не забыл? Конструировать формы так, чтобы родительский и дочерние блоки располагались в разных формах? Выполнять ввод значения в требуемое поле в отдельной форме или в отдельном блоке ? Все это часто неприемлемые варианты решения.
Автору известен способ обойти это ограничение. Не знаю, является этот способ единственно возможным или самым правильным, однако он успешно работает и вы можете воспользоваться им при необходимости. Однако, этот способ требует некоторых усилий при разработке формы.
Способ решения основан на том, что в триггере WHEN-NEW-ITEM-INSTANCE разрешено выполнения команд GO_BLOCK и EXECUTE_QUERY. В результате ввода значения в любое поле и выполнения затем триггера WHEN-VALIDATE-ITEM фокус ввода попадает на следующее поле или в то поле, на которое пользователь кликнул мышью после ввода значения. В результате срабатывает триггер WHEN-NEW-ITEM-INSTANCE того поля, которое получило фокус ввода. Вот здесь мы и можем перейти на любой требуемы нам блок и выполнить его обновление. Для этого в триггере WHEN-VALIDATE-ITEM поля, в котором осуществляется ввод, необходимо выставить флаг обновления дочернего блока, а в триггерах WHEN-NEW-ITEM-INSTANCE всех видимых на форме полей проверить флаг обновления дочернего блока и, при необходимости, выполнить это обновление, сбросив затем этот флаг.
Приведем пример. Предположим, что обновление для обновления дочернего блока у нас создана PL/SQL процедура с именем P$CHILD_REFR:
PROCEDURE P$CHILD_REFR
IS
BEGIN
go_block('CHILD');
execute_query;
END P$CHILD_REFR;
У нас в форме должен быть контрольный блок, например с именем B_CTRL, в который мы добавим поле IS_CHILD_REFR char(1), которое будет являться флагом, требующим обновления дочернего блока.
Создадим процедуру с именем P$CHECK_REFR:
PROCEDURE P$CHECK_REFR
IS
BEGIN
IF :B_CTRL.IS_CHILD_REFR='Y'
THEN
P$CHILD_REFR;
:B_CTRL.IS_CHILD_REFR:='N';
END IF;
END P$CHECK_REFR;
Затем добавим вызов процедуры P$CHECK_REFR в триггер WHEN-NEW-ITEM-INSTANCE всех видимых на форме полей.
В триггере
WHEN-VALIDATE-ITEM поля, в котором осуществляется ввод, добавим в любом месте строку:
:B_CTRL.IS_CHILD_REFR:='Y';
В принципе это все, в результате проделанной работы мы получим возможность автоматического обновления дочернего блока при изменении значения поля в родительском блоке.
Смотрите также:
Оставьте свой комментарий
Вы должны быть авторизированны, чтобы оставить комментарий.