Сохранение и получение данных CLOB размером более 32 КБ в Oracle Apex

Моя цель - получить данные CLOB из базы данных в текстовое поле в приложении Oracle Apex, а затем сохранить их в базе данных из самого текстового поля при нажатии кнопки «Сохранить». У меня также есть некоторые другие поля на этой странице (как текстовые поля), которые не являются полями CLOB, и их также необходимо сохранить в базе данных при нажатии кнопки.

Для этого я использую следующий код в разделе «Атрибут HTML-заголовка и тела» страницы. Это используется для получения / сохранения CLOB в текстовое поле / базу данных. Обратите внимание, что простого кода PLSQL внутри элемента Apex будет достаточно, чтобы делать то, что я делаю здесь, но только если данные CLOB меньше 32 Кбайт. Я использую эту функцию из-за ограничения в 32 КБ в plsql в вершине (и ограничения в 4 КБ при использовании sql).

function clob_set(){  
        var clob_ob = new apex.ajax.clob(  
            function(){  
                var rs = p.readyState  
                if(rs == 1||rs == 2||rs == 3){  
                    $x_Show('AjaxLoading');  
                }else if(rs == 4){  
                    $s('P5075_RESPONSETEXT',p.responseText);  
                    $x_Hide('AjaxLoading');  
                }else{return false;}  
            }  
        );  

        if(!$v_IsEmpty('P5075_STYLESHEET')){clob_ob._set($v('P5075_STYLESHEET'))};  
    }  

    function clob_get(){  
        var clob_ob = new apex.ajax.clob(  
            function(){  
                var rs = p.readyState  
                if(rs == 1||rs == 2||rs == 3){  
                    $x_Show('AjaxLoading');  
                }else if(rs == 4){  
                    $s('P5075_STYLESHEET',p.responseText);  
                    $x_Hide('AjaxLoading');  
                }else{return false;}  
            }  
        );  
        clob_ob._get();  
    }

Я вызываю одну из функций в разделе "Атрибут тела HTML страницы" как onload = "javascript: clob_get ();"

Для этого у меня есть PLSQL после процесса заголовка.

declare
l_clob clob:= empty_clob();

begin

if apex_collection.collection_exists(p_collection_name=>'CLOB_CONTENT') then
apex_collection.delete_collection(p_collection_name=>'CLOB_CONTENT');
end if;

apex_collection.create_or_truncate_collection(p_collection_name=>'CLOB_CONTENT');
dbms_lob.createtemporary( l_clob, false, dbms_lob.SESSION );

SELECT xslt
INTO l_clob
FROM schematransform
WHERE namn = 'f';

apex_collection.add_member(p_collection_name => 'CLOB_CONTENT',p_clob001 => l_clob);
end;

Это работает нормально. Теперь у меня есть процесс plsql, который сохраняет данные, введенные в поля CLOB и не-CLOB, в базу данных. Но как только страница отправляется, я получаю «неверный HTTP-запрос».

Может ли кто-нибудь объяснить, почему это происходит и как я могу это решить?


person Snow Leopard    schedule 09.07.2012    source источник
comment
Какая у вас апекс-версия? 4.0? 4.1? Ниже? Какой размер сгустка вы тестируете? Вы пробовали с клобуком ‹32k? Или ‹4к? Прочтите forum.oracle.com/forums/thread.jspa?threadID= 723735 и advnettech.net/blog/?p=7, похоже, они справляются с подобными проблемами и указывают на проблему с apex.ajax.clob и ›32k.   -  person Tom    schedule 10.07.2012
comment
Я использую Apex 4.1. Я тестировал размер CLOB от 90 до 50 КБ. У меня такая же проблема. Я правильно получаю CLOB в текстовом поле. Просто когда я вызываю функцию javascript при загрузке страницы, а затем отправляю страницу, я получаю эту ошибку. Процесс, сохраняющий текстовые поля, относится к типу анонимного блока PLSQL, а точка процесса - при загрузке - после заголовка. Этот процесс отправляется, когда я нажимаю кнопку «Отправить» с именем «Сохранить». Проблема, которую я вижу, заключается в некотором конфликте между «загрузкой страницы, вызывающей javascript» и «отправкой страницы» после этого.   -  person Snow Leopard    schedule 10.07.2012
comment
Я не уверен, правильно ли я понимаю: страница загружается, срабатывает при загрузке, вы получаете значения clob. Вы вносите правки. Вы нажимаете кнопку, которая отправляет страницу, и ожидаете, что поля со значениями clob будут сохранены в коллекции? Верный?   -  person Tom    schedule 10.07.2012
comment
Почти правильно. Я не сохраняю поля со значениями CLOB (пока). Помимо CLOB есть и другие поля (например, имя, заголовок), которые являются просто VARCHAR. При отправке я хочу сохранить эти значения в базе данных.   -  person Snow Leopard    schedule 10.07.2012
comment
Если ошибка возникает при отправке, возможно, вам нужно сначала удалить значение из элемента, содержащего clob, чтобы оно не отправлялось вместе с другими полями. Вы можете сделать это, отключив элемент или сделав его только отображаемым. Или вы можете перенастроить процесс отправки, чтобы сначала обнулить значение этого элемента.   -  person GregJarm    schedule 10.07.2012
comment
Грег, в этом есть смысл. Большое спасибо! Я двигался шаг за шагом. Вот почему я убрал клобуки из уравнения. Я получаю данные Clob в Техасской области. Я могу сохранить поля non clob в базе данных (сделав поле clob только отображаемым). Что я хочу сейчас: отправить страницу и сохранить детали clob (редактирование через textarea) и детали non clob в базе данных.   -  person Snow Leopard    schedule 11.07.2012
comment
Пожалуйста, извините меня за всю путаницу, я новичок в этом и все запутался, как действовать (и даже как объяснить).   -  person Snow Leopard    schedule 11.07.2012


Ответы (1)


Это код для apex.ajax.clob, взятый из apex_4_1.js:

/**
 * @namespace = apex.ajax
 */
apex.ajax = {
    /*clob*/
    clob : function (pReturn){
        var that = this;
        this.ajax = new htmldb_Get(null,$x('pFlowId').value,'APXWGT',0);
        this.ajax.addParam('p_widget_name','apex_utility');
        this.ajax.addParam('x04','CLOB_CONTENT');
        this._get = _get;
        this._set = _set;
        this._return = !!pReturn?pReturn:_return;
        return;
        function _get(pValue){
            that.ajax.addParam('x05','GET');
            that.ajax.GetAsync(that._return);
        }
        function _set(pValue){
            that.ajax.addParam('x05','SET');
            that.ajax.AddArrayClob(pValue,1);
            that.ajax.GetAsync(that._return);
        }
        function _return(){
        if(p.readyState == 1){
            }else if(p.readyState == 2){
            }else if(p.readyState == 3){
            }else if(p.readyState == 4){
              return p;
            }else{return false;}
        }
    },

Итак, установка и получение clob действительно асинхронны. Опубликованный вами код предоставляет функцию обработки, которая вызывается по завершении запроса (выполняется в htmldb_get). Я думаю, что это уродливый обходной путь, но все в порядке. Нам нужно манипулировать этим функциональным кодом, чтобы наша отправка работала. Поскольку набор является асинхронным, мы не можем быть уверены, что страница не будет отправлена ​​до того, как набор будет выполнен. Чтобы предотвратить это, измените свой код clob_set как таковой:

function clob_set(pSubmit){
   var clob_ob = new apex.ajax.clob(
      function(){
         var rs = p.readyState
         if(rs == 1||rs == 2||rs == 3){
            $x_Show('AjaxLoading');
         }else if(rs == 4){
             //here the clob has actually been saved, and
             // the ajax call finished
            $s('P5075_RESPONSETEXT',p.responseText);
            $x_Hide('AjaxLoading');

            //pSubmit is a new param
            //use it to check if set has been called for
            //a page submit or not
            if(pSubmit){
               //disable the clob field: it should not be
               //substituted to the session state!!
               $('#P5075_STYLESHEET').prop("disabled", true);
               //actually submit the page. This will submit
               //all fields to session except the disabled ones
               apex.submit('SUBMIT');
            };
         }else{
            return false;
         };
      });

   if(!$v_IsEmpty('P5075_STYLESHEET')){
      clob_ob._set($v('P5075_STYLESHEET'));
   };
};

Измените кнопку отправки, чтобы ее действие определялось динамическим действием. Вам нужно сделать это, чтобы предотвратить замену ваших полей clob в сеансе через процесс по умолчанию. Создайте динамическое действие, которое выполняет javascript, вызовите clob_set с установленным pSubmit:

clob_set(true);

Взгляните на apex.submit api описание. Также поймите, как работает кнопка: она отправляет страницу и устанавливает запрос на имя этой кнопки (или другое значение запроса, если оно определено явно).

Например, кнопка может называться «APPLY_CHANGES» и иметь метку «Изменить». Это важно, если вы используете, например, встроенную обработку строк. Значение запроса будет определять, какое действие SQL будет вызвано, и вы можете просмотреть возможные значения в деталях процесса, рядом с флажками для вставки / обновления / удаления.

Вот очень полезная красивая блок-схема:

блок-схема clob_set

person Tom    schedule 11.07.2012
comment
Прости, Том, я не смог заставить его работать. Чтобы быть ясным, вы говорите мне, как вставлять поля CLOB и не CLOB в базу данных, верно? - person Snow Leopard; 12.07.2012
comment
Что я пытаюсь сделать, так это не позволять полям, содержащим значение clob, передаваться в сеанс, поскольку мы хотим избежать там ограничений в 32k. Тем не менее, неколубы должны обрабатываться нормально. Итак, я хотел здесь сначала сохранить эти поля clob через clob_set, затем отключить эти поля clob и затем отправить страницу. Это должно привести к тому, что ваше значение clob будет в коллекции, а другие ваши элементы будут в состоянии сеанса. Я надеюсь, что clob_set сделает то, что вы / я / мы ожидаем от него! Если у вас есть код ошибки или около того, опубликуйте его. Если мой метод неясен, может быть, поможет пример? - person Tom; 12.07.2012
comment
О, ладно, теперь я понял. Большое спасибо за прекрасное объяснение. Теперь, когда я это понял, позвольте мне сделать все, что в моих силах. Я дам вам знать, если что-то получится или нет. Хороших выходных :) - person Snow Leopard; 13.07.2012
comment
Привет том! Я пробовал с динамическими действиями. Поля non clob теперь сохраняются без проблем. Поля CLOB сохраняются, но в этом есть проблема. Мне нужно дважды нажать кнопку «Сохранить», чтобы сохранить его в базе данных. Вот что я сделал. Я вызвал clob_get () в нижнем колонтитуле области, содержащей поле clob, чтобы получить данные clob, как только страница загрузится. - person Snow Leopard; 16.07.2012
comment
Я сделал динамическое действие на кнопке «Сохранить», указав событие как «Щелчок». Имею 2 верных действия. 1-й - «Выполнить код Javascript», который вызывает clob_set () при нажатии кнопки, а 2-й - «Выполнить код plsql», который сохраняет поля clob и non clob в базе данных. Область действия в динамическом действии - привязка. - person Snow Leopard; 16.07.2012
comment
Я внес небольшое изменение в clob_set (), которое опубликовал выше. Я использовал элемент текстового поля «P5075_RESPONSETEXT», который получает сообщение как «SUCESS», если вызывается clob_set (). В моем случае, когда я нажимаю кнопку «Сохранить», я получаю текст «Успешно» в элементе, а затем снова, если я нажимаю «Сохранить», сгусток сохраняется в базе данных. Я понимаю, что это происходит, поскольку мое динамическое действие выполняется «по щелчку», но я не мог понять, как это исправить, потому что, если я изменю его на «onchange» или что-то в этом роде, то у меня снова возникнет проблема 32k. - person Snow Leopard; 16.07.2012
comment
Я считаю, что есть некоторые ошибки / недопонимания. Во-первых: я совершил ошибку: clob_set - это ajax, и, вероятно, истинный ajax (в отличие от многих других функций в apex, которые действительно синхронны). Поэтому вызывать эту функцию и сразу же после нее вызывать ненадежно. Во всяком случае, ваша измененная обработка также может быть изменена: нет необходимости изменять ваш clob на DB с помощью динамического действия. clob_set сохраняет ваше поле clob в коллекцию, я бы просто написал процесс после отправки, который затем сохраняется из коллекции в БД. Ваш поток станет намного яснее. - person Tom; 16.07.2012
comment
Что вы имеете в виду под процессом последующей отправки в Apex? Вы имеете в виду процесс «по запросу»? И в этом случае, где и когда мне вызывать clob_set ()? - person Snow Leopard; 16.07.2012
comment
clob_set должен вызываться через javascript, прежде чем что-либо будет отправлено. Иметь это одним нажатием кнопки - хорошо. Под процессом после отправки я подразумеваю создание нового процесса: не по запросу! Точка обработки должна быть после отправки или даже после проверки. Я говорю это, потому что нет необходимости сохранять ваши значения clob в БД через ajax и до того, как в вашей форме будет проведена какая-либо проверка. Наличие этого процесса в фактическом потоке обработки страницы будет намного понятнее, чем его скрытие в js-коде. - person Tom; 16.07.2012
comment
посмотрите фантастическую блок-схему, которую я добавил в свой пост, может быть, это прояснит - person Tom; 16.07.2012
comment
Хорошая блок-схема Тома! В соответствии с ним, теперь, когда моя кнопка «Сохранить» выполняет вызов javascript для clob_set (), иногда поле «RESPONSETEXT» получает «УСПЕХ», а иногда выдает ошибку «Запрошенный URL-адрес /apex/wwv_flow.show был не найден на этом сервере ». Это совершенно случайно. Иногда это работает, иногда нет. Есть комментарии по этому поводу? (Прямо сейчас я не продвинулся вперед в этом шаге, так как это нужно сначала решить) - person Snow Leopard; 16.07.2012
comment
и когда я отправляю страницу, я возвращаюсь к исходной точке, когда я разместил вопрос. Отправить не работает. Это дает мне «Плохой запрос». Я так запутался. - person Snow Leopard; 16.07.2012
comment
Хорошо: во-первых. Вы изменили щелчок по отправке. Вы сделали это, как я описал, то есть без кнопки «отправить», но заставили кнопку запускать динамическое действие? Есть ли в этом динамическом действии опубликованный мной код (особенно важно отключение поля clob)? Если да для обоих: вы тестируете свое поле clob с большим количеством данных? Вы пробуете с ›30k? Просто убеждаюсь. - person Tom; 16.07.2012
comment
Я снова отредактировал свой пост, надеюсь, еще лучше объяснил, что (или может быть) происходит - возможно, ajax пока портит вечеринку! - person Tom; 16.07.2012
comment
Извините, я кое-что неправильно понял. Хорошо, теперь я делаю, как ты сказал. Моя кнопка СОХРАНИТЬ определяется динамическим действием. Динамическое действие срабатывает при нажатии кнопки «СОХРАНИТЬ» и имеет следующий код javascript: clob_set (); $ ('# P5075_STYLESHEET'). Prop (отключено, истина); apex.submit («СОХРАНИТЬ»); Затем я создал процесс, который запускается после отправки и сохранения полей clob и non clob в базе данных. Мои данные, не связанные с Clob, сохраняются. Однако данные сгустка НЕ ​​сохраняются. Я пробую как для данных ›32K, так и‹ 32K. Оба имеют одинаковые результаты. - person Snow Leopard; 16.07.2012
comment
Взгляните на JS-код, который я редактировал для динамического действия. Теперь, когда ваш clob_data не сохраняется: в вашем процессе, как вы получаете содержимое вашего clob? Выбираете из коллекции? (выберите clob001 из apex_collections, где collection_name = 'CLOB_CONTENT')? Это вызывает no_data_found? Попробуйте пошагово выполнить обработку вашей страницы с включенной отладкой, может быть, вы что-то заметите? - person Tom; 16.07.2012
comment
Я отредактировал свою функцию clob_set () и сделал вызов динамического действия, как вы предложили. Да, я получаю содержимое clob в процессе из коллекции (выберите clob001 в v_clob из apex_collections, где collection_name = 'CLOB_CONTENT';). Я использую это значение (через переменную v_clob), чтобы установить столбец CLOB в базе данных с помощью оператора обновления. Нет, я не получаю сообщение об ошибке «данные не найдены» (ничего не могу обнаружить даже при включенной отладке). - person Snow Leopard; 16.07.2012
comment
Хорошо, это будет означать, что сгусток действительно имеет ценность. Добавьте «COMMIT;» в конце процесса и посмотрите, поможет ли это! Если это не так, покажите сообщение отладки с помощью apex_debug_message.log_message (v_clob) и проверьте его с помощью отладки. Если это пусто, ошибка должна быть с clob_set (D :) - person Tom; 16.07.2012
comment
Том, я допустил небольшую опечатку, теперь это работает как шарм! Большое вам спасибо за то, что вы помогали мне на протяжении всего пути. Я перефразирую свой первоначальный вопрос, чтобы позже он мог помочь другим. Спасибо еще раз :) - person Snow Leopard; 16.07.2012