Модификация.
Часто при работе с Oracle Forms требуется реализовать
возможность программного выполнения последнего запроса пользователя.
Например, вы стоите на некоторой записи в блоке и нажимаете на кнопку,
которая вызывает процедуру(часто хранимую), модифицирующую текущую
запись. После того как процедура отработала и запись была успешно
модифицирована требуется обновить содержимое блока в форме для
отображения сделанных изменений.
Выполнить последний запрос в блоке интерактивно - довольно просто, достаточно последовательно нажать на клавиши:
ENTER_QUERY (<F7>) ENTER_QUERY (<F7>) EXECUTE_QUERY (<F8>)
Однако попытка последовательно выполнить соответствующие встроенные процедуры:
ENTER_QUERY; ENTER_QUERY; EXECUTE_QUERY;не приводит к желаемому. Форма после первой ENTER_QUERY переходит в режим ввода запроса и так в нем и остается.
Пакет P_QUERY предназначен для решения данной проблемы.
Для подготовки к использованию требуется наличие в форме пакета P_QUERY (Program Units, Attached libraries) и четыре вида триггеров.
Также, требуется расставить по нужным местам (триггерам) четыре процедуры этого пакета:
Где разместить эти процедуры.
Триггеры уровня формы:
1.PRE-FORM:
В этом триггере для каждого блока, в котором хотим перевыполнять запрос,
нужно вызвать процедуру:
P_QUERY.Init_New_Block ('<block_name>', '<primary_key_column>');
, где
<block_name> - имя блока, например 'EMP'
<primary_key_column> - название столбца первичного ключа, например 'EMPNO'
Это вовсе не значит, что этот столбец нужно объявить первичным ключом в блоке
формы.
2. POST-FORM
P_QUERY.Finalize;
Триггеры уровня блока. Для каждого определенного в PRE-FORM блока нужно создать два триггера:
3. PRE-QUERY P_QUERY.Prepare_Last_Query; 4. POST-QUERY P_QUERY.Find_Row;
Важное замечание.
Предполагается что только в элементы следующих типов можно вводить
условия запроса: 'CHECKBOX', 'DISPLAY ITEM', 'LIST', 'RADIO GROUP', 'TEXT ITEM'
Более того, для того чтобы элементы этих типов обрабатывались, необходимо
чтобы их свойство 'Column Name' было ЗАПОЛНЕНО.
Подготовка закончена.
Теперь в любом месте где нужно программно выполнить последний запрос вызываем:
P_QUERY.Exec_Last_Query;
Запрос будет перевыполнен в текущем блоке. Если нужно это сделать для другого блока, то требуется предварительно перейти в него.
Помимо программного выполнения последнего запроса, процедура Exec_Last_Query выполнит позиционирование в тоже поле, той же записи, где находился курсор перед вызовом.
Если вы программно добавляете новую запись (например через вызов хранимой процедуры) и хотите автоматически переместиться в блоке на только что добавленную запись, то можете выполнить:
P_QUERY.Exec_And_Goto ('<значение PK новой записи>');
Запрос будет перевыполнен и курсор перейдет на запись с указанным значением первичного ключа.
Для того чтобы проверить правильность позиционирования, можно воспользоваться функцией P_QUERY.Last_Query_Success. Эта функция вернет TRUE в случае если искомая запись была найдена и FALSE в противном случае.
Прочие публичные подпрограммы пакета P_QUERY были созданы для отладочных целей и не должны использоваться.
Принцип работы основывается на использовании триггера PRE-QUERY. В этом триггере находится процедура (Prepare_Last_Query), которая по умолчанию запоминает значения всех полей блока, в которые разрешено вводить условия запроса.
Т.к. триггер PRE-QUERY срабатывает непосредственно перед выполнением запроса, а значения полей блока полученные в нем и есть те критерии поиска, вводимые пользователем в режиме ENTER_QUERY, то запомнив их, мы имеем всю необходимую информацию для того, чтобы в дальнейшем перевыполнить этот же запрос.
Для этого нужно в процедуре перевыполняющей запрос (Exec_Last_Query), перед вызовом EXECUTE_QUERY установить специальный флаг для Prepare_Last_Query, чтобы последняя вместо запоминания значений полей, наоборот, восстановила ранее запомненные критерии поиска в соответствующие поля блока.
Использование данной утилиты предполагает, что если требуется программно установить некие критерии поиска, то это делается не установкой свойста DEFAULT_WHERE для блока, а также - через триггер PRE-QUERY. Вызов процедуры Prepare_Last_Query в этом случае должен быть последним в триггере.
Для автоматической навигации после выполнения запроса в тоже поле, той же записи, процедура Exec_Last_Query должна сначала запомнить в каком поле находится курсор и в какой записи. Для идентификации текущей записи используется информация введенная при вызове Init_New_Block в стартовом триггере формы. При вызове этой процедуры определяется значение какого поля блока будет однозначно идентифицировать запись.
Недостатки текущей реализации
FIRST_RECORD; LOOP NEXT_RECORD; /* Проверка очередной записи */ EXIT WHEN _искомая_запись_найдена_или_последняя_запись; END LOOP;
Главный минус используемого подхода в том, что требуется еще один триггер - POST-QUERY.
Сдедано так как сделано потому, что одно время у меня было убеждение(или заблуждение), что NEXT_RECORD в цикле - очень медленно и GO_RECORD будет гораздо быстрее. Однако предварительные тесты показали, что "оверхэд" на запуск POST-QUERY "съедает" всю возможную быстроту GO_RECORD.
Опять же, переделать не сложно... в планах.
Тестовая форма F_QUERY содержит один блок данных построенный по представлению USER_OBJECTS и демонстрирует возможности утилиты. В этой же форме находится собственно пакет P_QUERY.
15 Июля 2002 года.