Application Express:匿名PL / SQL块和绑定变量

时间:2014-05-28 19:24:30

标签: plsql oracle11g oracle-apex

我遇到了将页面项的值绑定到匿名PL / SQL块进程中的声明变量的问题。

问题是页面项(:P4550_REQUESTOR)在满足条件之前没有填充值。看起来PL / SQL块进程在加载页面后立即将变量绑定到空值,尽管在单击特定按钮之前该过程不会触发。

这是我的代码:

DECLARE 

v_email_to   app_user.email%type;
v_requestor  VARCHAR2(15);

BEGIN

  v_requestor := :P4550_REQUESTOR;

BEGIN
    SELECT email INTO v_email_to
    FROM app_user 
    WHERE userid = v_requestor;
END;

SEND_APEX_MAIL (
                 v_email_to,

                 'Your vacancy request has been rejected.'
                 || chr(10)
                 || 'Emailed to: ' || v_email_to
                 || chr(10)
                 || 'Requestor: ' || v_requestor,

                 'Vacancy Request Rejected' 
               );

END; 

有没有人对此有任何想法?

如果我将值硬编码到v_requestor,那么块工作正常。如果我在页面加载后尝试获取P4550_REQUESTOR的值,则为空。单击编辑按钮后,将填充P4550_REQUESTOR。

** **更详细** **

P4550_REQUESTOR是位于空缺请求区域内的页面项目,仅在满足条件时显示。具体而言,条件是与在页面加载时创建的表行相关联的编辑按钮。单击编辑按钮将显示详细信息区域,以及要填充的关联页面项。

空缺请求区域中的页面项值通过自动行提取填充,该提取在标题之后触发。

P4550_REQUESTOR的源类型为DB列。

触发上述代码的过程设置为触发提交 - 计算和验证后

如果我在页面加载时记录P4550_REQUESTOR的值,则显示为null。如果我在单击编辑按钮后记录该值,则会得到预期的字符串值。

2 个答案:

答案 0 :(得分:3)

Oracle APEX中的流程控制

(这在其他编程学科和环境中考虑实际上很有用。)

问题定义

  

问题是页面项(:P4550_REQUESTOR)在满足条件之前没有填充值。看起来PL / SQL块进程在加载页面后立即将变量绑定到空值,尽管在单击特定按钮之前该过程不会触发。

问题陈述重写了Apex术语,并以实际问题的形式呈现:

  
      
  1. 页面上有一个REPORT REGION,其中包含对数据表/视图的直接引用的结果。此报告由名为" Automated Fetch"的Apex流程管理。并通过加载页眉自动启动。
  2.   
  3. 页面上有FORM ITEM,有条件地由用户进行的BUTTON ITEM选择填充。 BUTTON ITEM是报告结果的一部分。
  4.   
  5. 有多个按钮项。每个都与每个报告记录的值相关联。
  6.   
  7. 如果用户未选择BUTTON ITEM中的REPORT REGION,则FORM ITEM仍然未分配且包含" null"值。
  8.   

有一个已定义的PL / SQL代码块,设置为在按下SUBMIT BUTTON项目时执行(也在同一页面上)。为什么我的代码块(已定义的页面处理)在没有先从BUTTON ITEM首先按下REPORT REGION的情况下被触发时使用空值运行?

程序编程人员的事件驱动程序设计

如果你在程序语言的范式下思考,答案就不明显了。如果没有深入研究这个主题的演讲,我可以通过这种方式对OP的问题空间进行视觉布局,以说明如何使问题更加明显:

Oracle Apex Page Design Notation

这是我实现的Apex页面设计。它的通用性足以用作其他Apex设计的模板。此图中没有流向箭头,因为它是一个有状态系统。有一件事会导致另一件事情发生,等等......但并非总是而且并非所有事情都在同一时间。

Apex UI页面设计的用例

尝试浏览一些用例,了解图中分解的元素如何一起运行。每个用户可以采用任意数量的点击组合和互动,但有一个共性:

  1. 他们都在页面加载时输入相同的初始化条件。
  2. 他们都离开了页面:在其他地方导航或通过SUBMIT按钮事件。
  3. 使用案例#1

    1. 用户从{MyPage:SQLReport:ThisButton}
    2. 中的一个记录中选择{MyPage:SQLReport}
    3. 根据{MyPage:SQLReport:ThisButton} #3,报告记录与按钮项目之间关联的值将传递到:{MyPage:HTML-Region:ThisItem}
    4. 表单项状态已更新并从初始空值更改。
    5. 用户选择{MyPage:HTML-Region:ThisSubmit}按钮通知系统继续。
    6. 提交按钮执行定义的PL / SQL过程块:{MyPage:RunCodeBlock}
    7. 使用案例#2

      1. 用户输入页面并查看{MyPage:SQLReport}区域中显示的结果。
      2. 用户决定不需要其他输入,然后选择{MyPage:HTML-Region:ThisSubmit}按钮通知系统继续。
      3. (注意:表单项{MyPage:HTML-Region:ThisItem}的状态此时尚未从初始空值更改...选择了提交按钮后)
      4. 提交按钮执行定义的PL / SQL过程块:{MyPage:RunCodeBlock}
      5. 使用案例#3

        1. 用户从{MyPage:SQLReport:ThisButton}
        2. 中的一个记录中选择{MyPage:SQLReport}
        3. 根据{MyPage:SQLReport:ThisButton} #3,报告记录与按钮项目之间关联的值将传递到:{MyPage:HTML-Region:ThisItem}
        4. 表单项状态已更新并从初始空值更改。
        5. 用户从{MyPage:SQLReport:ThisButton}中的一条记录中选择不同选项中的{MyPage:SQLReport}
        6. 根据{MyPage:SQLReport:ThisButton} #3,报告记录与按钮项目之间关联的值将传递到:{MyPage:HTML-Region:ThisItem}
        7. 表单项状态已从步骤(2)中存储的初始值更新和更改。
        8. 用户选择{MyPage:HTML-Region:ThisSubmit}按钮通知系统继续。
        9. 提交按钮执行定义的PL / SQL过程块:{MyPage:RunCodeBlock}
        10. 每个案例之间的差异应说明为什么依赖值(ThisItem,或更具体地说,页面项P4550_REQUESTOR)在一个用例中与另一个用例相比为空。

          构建物理实现(Apex页面)

          我使用的表名为STAR_EMPS。它类似于EMP表,但只有三列:ename,deptno和salary。虽然它不是非常重要,但这是我用来填充STAR_EMPS的数据集:

          Test Data for the STAR_EMPS table

          我使用了一个名为STAR_EMPS_LOG的简单双列表来捕获成功执行的过程调用的输出。您可以只使用一列完成相同的操作,但我想要一个用于跟踪每个事件记录顺序的顺序ID - 用于运行多个测试用例。该过程是此页面上保留的几个已定义过程之一:

          MyPage Page Processes

          包含在:{MyPage:RunCodeBlock}如下:

              DECLARE
                -- output from this procedure will be recorded in the star_emps_log
                -- table.  {MyPage:RunCodeBlock}
          
                mycelebrity  star_emps.ename%TYPE:= :P17_CELEBRITY_NAME;
                mylogmessage star_emps_log.log_message%TYPE;
          
              BEGIN
                -- Conditional; changes message based on the value set for the
                -- page item.
          
                   if mycelebrity is null then
                   mylogmessage:= 'No button was pressed on the previous page.';
               else 
                   mylogmessage:= 'The user selected: ' || mycelebrity ||
                   ' from the report list.';
               end if;
          
               -- populate value from the page item.
                  INSERT INTO star_emps_log (log_message)
                     VALUES (mylogmessage);
                  commit;
          
              END;
          

          这是页面布局的设置方式:

          Physical Layout of Regions for "MyPage"

          1. 在您的示例中,我创建了一个{MyPage:SQLReport}区域及其支持元素。 SQL报告表示针对源数据表的查询。
          2. {MyPage:Form}已 重命名 至{MyPage:HTML-Region}。
          3. {MyPage:SQLReport}是由SQL查询定义的,还有一个模拟列用作占位符,用于放置"编辑"的按钮。
          4. {MyPage:SQLReport:ThisButton}按钮规范详细说明如下:
          5. Input Button is Defined as...

            Establishing a Link With a triggering event (submit button)

            TWO Page进程:PROCESS和BRANCH需要使用引用BUTTON触发项的相同设置进行链接。

            用户界面测试用例

            运行三个建议的方案开始。验证系统是否正确解释请求。这就是页面布局的样子:

            Mobilizing the QA Test Plan

            系统上的两个流程有一个定义,以前的讨论中没有提到可以解决我们手头的原始问题:

            enter image description here

            一些离别的想法

            一旦被打破,这是一件好事,事实证明这是一个微不足道的案例。这里描述的图表方法应该扩展到不同复杂度的其他Apex应用程序。脱离代码,锁定术语并试图在没有实际代码的情况下描述系统和流程,具有相当大的实用性。如果这种方法有助于您自己的Oracle Apex设计挑战,请务必分享任何故事。

            冠!

答案 1 :(得分:0)

原始的,冗长的答案似乎使问题过于复杂。 session state concepts manual更简洁地涵盖了这种行为。

P4550_REQUESTOR应该是从向导创建的正常项目,使用:P4550_REQUESTOR将在提交后运行的进程中返回一个值,因为提交进程会将浏览器中的值移动到会话状态。

如果P4550_REQUESTOR有条件地呈现,那么它将始终为null并且我不确定如果你试图设置它会发生什么 - 可能取决于如何。

在类似的说明中,如果您使用了& P4550_REQUESTOR。要对进程进行参数化,您将面临最初描述的行为(并使代码不太安全)