Oracle DB, Oracle APEX, Linux etc.

суббота, 28 мая 2011 г.

Oracle APEX 4.0: Небольшой пример плохой реализации

Сегодня я хотел бы упомянуть о том, как не надо разрабатывать. И в качестве примера у нас будет... APEX 4.0 Application Builder. Думаю, все разработчики приложений, использующие эту среду, видели страницу атрибутов элемента, динамического действия или региона. Например, выбираем у элемента Display As=Select List - и появляется регион List of Values с соответствующими настройками. В общем, ту страницу, на которой в зависимости от типа объекта атрибуты и регионы прячутся и показываются в зависимости от выбранных значений.

Отличная цель: оживить и разгрузить страницу, убирая неподходящие поля с глаз долой.

Плохая реализация: при загрузке страницы показываются все элементы страницы, а уже потом Dynamic Actions прячут ненужное, запускаясь после полной загрузки страницы. Это здорово, что у динамических действий есть возможность запуска при загрузке страницы (флажок Fire On Page Load). Но когда пользователь видит мельтешащие поля, которые только что были, а потом куда-то пропали - это ужасно. И с эстетической точки зрения, и с точки зрения здравого смысла. Зачем показывать, а потом тут же (а иногда - и не тут, если страница загружается медленно) скрывать часть интерфейса? Лучше не показывать её вообще.

Как стоило сделать: воспользоваться возможностью указать соответствующий CSS-стиль в свойствах региона, элемента и в их шаблонах. Скрыть всё то, что показывается динамически в зависимости от каких-либо условий.
display: none;
Не отмечать Fire On Page Load у действий, которые что-либо скрывают. (Потому что они сохраняют старое значение свойства display и потом используют его при показе элемента.) Отмечать Fire On Page Load у действий, которые что-либо показывают. Как итог, на странице появятся вначале все обязательные настройки, а потом отобразится все доступные для изменения настройки.

Предложенный мной способ более трудоёмкий и требует больше времени от разработчика приложения. Но и приложение не будет "моргать" элементами интерфейса перед пользователем при каждой загрузке страницы. Мне кажется, это того стоит.

PS: Вышеописанный подход, в принципе, касается не только приложений APEX. Чем меньше пользователь видит ненужного, чем меньше зряшной работы выполняет приложение, тем лучше.

Читать далее

понедельник, 14 февраля 2011 г.

Oracle APEX: Collections Debug 2

Есть более "честный" способ для работы с коллекциями при отладке: можно установить соответствующие значения в переменных окружения APEX, частично "клонировав" интересующую сессию. Я для этого использую простую процедуру:

create or replace procedure copy_apex_session_env 
  ( p_session_id apex_workspace_sessions.apex_session_id%type
  , p_app_id apex_applications.application_id%type )
as
  l_session apex_workspace_sessions%rowtype;
  l_app_id apex_applications.application_id%type;
begin
  begin
    select * into l_session
      from apex_workspace_sessions s 
     where apex_session_id = p_session_id;
  exception
    when no_data_found then
      raise_application_error(-20001, 'Invalid Session ID!');
  end;
  
  begin
    select application_id into l_app_id
      from apex_applications
     where application_id = p_app_id
       and workspace_id = l_session.workspace_id;
  exception
    when no_data_found then
      raise_application_error(-20002, 'Invalid Application ID!');
  end;  
  
  apex_custom_auth.set_session_id(p_session_id => l_session.apex_session_id);
  apex_custom_auth.set_user(l_session.user_name);
  wwv_flow_api.set_security_group_id(l_session.workspace_id);
  apex_application.g_flow_id := l_app_id;
end copy_apex_session_env;
/

Она должна создаваться в схеме разбора приложения (без этого не сработает wwv_flow_api.set_security_group_id). Теперь, чтобы увидеть данные соответствующей коллекции, достаточно вызвать процедуру и выполнить запрос:

exec copy_apex_session_env(p_session_id => &session_id, p_app_id => &app_id);

select * from apex_collections where collection_name = 'YOUR_COLLECTION_NAME';

Читать далее

понедельник, 7 февраля 2011 г.

Oracle APEX: Collections Debug

Самый простой, хоть и не очень честный способ отладки при работе с коллекциями APEX - смотреть в таблицы wwv_flow_collections$ и wwv_flow_collection_members$ схемы, в которую установлен APEX. Если, конечно, есть соответствующие права, и известны приложение (FLOW_ID) и сессия (SESSION_ID), работающие с коллекцией.
Читать далее

понедельник, 27 декабря 2010 г.

Пара фраз о JSON

Вначале - о проблеме. Сколько раз сталкиваюсь, что JSON-парсер в Firefox вдруг по какой-то причине спотыкается на казалось бы правильной JSON-строке. Решение довольно простое - завернуть эту строку в обычные скобки:

  var result = JSON.parse("("+json_string+")");

Теперь - о довольно удобном средстве работы с JSON из PL/SQL. Вам хочется организовать эту работу так?

declare
  l_json json := json();
begin
  l_json.put('name', 'Taras');
  l_json.put('sons', json_list('["Mykola", "Vasyl"]'));
  htp.p(l_result.to_char);
end;
/

Тогда обратите своё внимание на проект PL/JSON. Думаю, он облегчит Вам жизнь - особенно, если Вы не поленитесь просмотреть короткие уроки.
Читать далее

пятница, 10 декабря 2010 г.

Oracle APEX: Медвежья услуга при копировании страницы

С прискорбием вынужден сообщить, что как минимум в версиях 3.2.1 и 4.0.1 я наткнулся на неприятный баг. При копировании страницы автоматически заменяются имена старых элементов: PMXXX заменяется на PNXXX, где M и N - номера оригинальной страницы и копии, соответственно. Проблема в том, что стоило бы заменять PM_XXX.

Для примера: у нас есть страница 5, которая где-то - в переходах, в значении элемента, в процессах - ссылается на элемент P52_X страницы 52. Теперь мы решили скопировать страницу 5 с новым номером 60. После копирования новая страница будет ссылаться на несуществующий элемент P602_X: было 52, стало 602.

Вот такая неприятная штука.
Читать далее

понедельник, 29 ноября 2010 г.

Oracle: Consistency и разминка для ума

Допустим, что в одной сессии выполнится следующее:

drop table t7;
create table t7 as select 1 id, 0 val from dual;
insert into t7 values(2, 0);
update t7 set val = 1;

Затем во второй выполнилось вот это:

update t7 x set val = (select t.val + 1 from t7 t where t.id = x.id);
commit;
select * from t7;

Что выведется во второй сессии на экран?

Теперь повторим в первой сессии тот же блок, что и вначале, а во второй выполним:

update t7 x set val = (select x.val + 1 from t7 t where t.id = x.id);
commit;
select * from t7;

Каким будет результат?

PS: Ответы и информацию для размышления опубликую через пару дней.
Читать далее

суббота, 20 ноября 2010 г.

Oracle APEX: Сколько транзакций в фазе Page Processing?

И правильный ответ... Одна.

Из любопытства я сделал простой тест, чтобы подтвердить, что обработка страницы происходит в одну транзакцию:

0. Создал таблицу и пакет для лога.

create table processing_steps (ordr number, msg varchar2(1000 char));

create or replace package proc_stp_pkg
as
  procedure reset;
  procedure add(p_ordr number, p_msg varchar2);
  procedure add_auton(p_ordr number, p_msg varchar2);
end proc_stp_pkg;
/

create or replace package body proc_stp_pkg
as
  procedure reset
  is
    pragma autonomous_transaction;
  begin
    delete processing_steps;
    commit;
  end;
  
  procedure add(p_ordr number, p_msg varchar2)
  is
  begin
    insert into processing_steps(ordr, msg) values (p_ordr, p_msg);
  end;
  
  procedure add_auton(p_ordr number, p_msg varchar2)
  is
    pragma autonomous_transaction;
  begin
    add(p_ordr=>p_ordr, p_msg=>p_msg);
  
    commit;
  exception
    when others then 
      rollback;
      raise;
  end;
end proc_stp_pkg;
/

1. Создал в APEX страницу с процессом перед проверками, вычислением, проверкой и процессом после вычисления. В каждом из них есть строки:

rollback;
proc_str_pkg.add(..., '...');
proc_str_pkg.add_auton(..., '...');

2. Добавил кнопку и переход на эту же страницу при нажатии.
3. Запустил страницу и нажал на кнопку.
4. Выполнил запрос:

SQL> set pages 9999 line 200
SQL> column msg format a50
SQL> select * from processing_steps
  2  order by ordr;

      ORDR MSG
---------- --------------------------------------------------
         1 Pr: On Submit - Before Computations and Validation
           s - Autonomous Transaction

         3 Computation - Autonomous Transaction
         5 Validation - Autonomous Transaction
         6 Pr: On Submit - After Computations and Validations
         7 Pr: On Submit - After Computations and Validations
            - Autonomous Transaction


SQL>

Пропущенные вставки 0, 2 и 4 откатывались оператором ROLLBACK в последующих блоках обработки. Вставка 6 автоматически зафиксировалась при успешном выполнении последнего блока. Так что будьте осторожней, управляя фиксацией и откатом в Вашем коде - Вы можете повлиять на результаты предыдущих блоков.

Читать далее