Oracle Form二次开发实战总结

操作数据无非删除、更新、插入的动作,在Oracle Form依靠下面触发器完成这些操作。

Form  Trigger

Key-commit    保存按钮触发/Ctrl+S 键盘触发/代码触发

Block  Trigger

Pre-delete        Pre-update       Pre-insert

On-delete        On-update       On-insert       On-lock 

Oracle保存数据的机制:第一步依次从数据库中删除在Block上删除的记录(删除每条记录时先触发Pre-delete,再触发On-delete),第二步依次从数据库中更新在Block上更新的记录(更新每条记录时先触发Pre-update,再触发On-update),第三步依次向数据库中插入在Block上插入的记录(插入每条记录时先触发Pre- insert,再触发On- insert),第四步COMMIT。其中任何一步出错的话都会引发异常,回滚以前的操作。所以我猜想Oracle Form肯定有一套机制能记录Block上每条记录的状态,所以在保存时可触发相应的Trigger

如果限制Form在一定条件下才允许保存,可以将控制逻辑写在Formtrigger pre-commit或者block级的Pre-deletePre-updatePre-insert代码中(这种情况控制可以针对操作类型进行控制,更加精细),一但条件不满足,立即抛出异常或忽略本次操作。

On-lock触发器在用户在界面上企图修改数据时触发,利用了Oracle悲观封锁的机制,保证数据的完整性和一致性.

在需要设置who字段的block中,Pre-insertPre-update都要添加如下代码:

fnd_standard.set_who; oracle会调用API给那几个who字段赋值,不用我们操心了。

另外在pre-insert的触发器中设置某些 Item 的初始值,比如说给org_id字段赋值,比如给一个主键 Item赋一个sequence.nextval,这样与在Iteminitial value属性中设定sequence.nextval

相比可以节省很多序列号,也可以更好保证序列号的连续性,这在某些业务中是非常关键的。

    Eg:

    :BLOCKNAME.ITEM_NAME := FND_PROFILE.VALUE(‘VALUE_NAME’);

    SELECT  SEQUENCE_A.NEXTVAL INTO :BLOCKNAME.ITEM_NAME ; 

操作数据前提是设置BlockInsert_AllowedUpdate_AllowedDelete_Allowed属性为Yes,对于数据源为基表,单表视图或简单多表视图,可以利用Oracle Form自身的机制,不需借助任何代码,可以实现数据的操作。

1.操作基表和单表视图

Block

Property               Value          Note

DML Data Target Type     Table

2.操作多表视图

Block                 

Property               Value          Note

DML Data Target Type     Table

DML Data Target Name    Table_Name     操作的基表名

Item(主键字段)

Property               Value          Note

Primary Key             Yes            不指定主键的话编译会出错

以上2种情况,系统会自动构造InsertUpdateDeleteLock语句。根据我Trace的结果来看,

UpdateDeleteLock都是根据记录的ROWID来唯一确认一条记录的。

3.使用代码操作数据

对于数据的操作,我都建议用代码实现,这样比较直观,出了问题也容易找到原因。Oracle Form会分别调用ON-INSERT触发,ON-UPDATE触发,ON-DELETE触发分别完成插入、更新、删除操作。需要注意的是:在符合上面12类型的情况下,创建了ON-XXXXXX触发器,都里面的代码为NULL;这时候系统就不能自动操作数据了,因为Oracle Form检测到了ON-XXXXXX触发器,执行了其中的代码,即执行了 NULL;语句。

PROCEDURE INSERT_ROW  IS

      CURSOR c is

              select      return_fix_headers_id

         from     TVSN_RETURN_FIX_HEADERS_ALL

              where     return_fix_headers_id = :HEADER.return_fix_headers_id ;

BEGIN

insert into TVSN_RETURN_FIX_HEADERS_ALL

            (return_fix_headers_id ,line_type ,order_header_id          

            ,f_to_r_flag ,ORG_ID ,creation_date ,… ,attribute15  )

        values

            (:HEADER.return_fix_headers_id             

  ,:HEADER.line_type ,:HEADER.order_header_id          

 ,:HEADER.f_to_r_flag  ,:PARAMETER.G_ORG_ID                                   

  ,…   ,:HEADER.attribute15 ) ;

      open c ;

      fetch c into :HEADER.return_fix_headers_id ;

      if (c%notfound) then close c ;

           raise no_data_found ;

      end if ;

      close c ;    

END INSERT_ROW;

PROCEDURE UPDATE_ROW is      

BEGIN

       update TVSN_RETURN_FIX_HEADERS_ALL

       set

       return_fix_headers_id   = :HEADER.return_fix_headers_id

       ,line_type                        = :HEADER.line_type      

       ,order_header_id           = :HEADER.order_header_id          

       ,f_to_r_flag                    = :HEADER.f_to_r_flag           

       ,org_id                             = :HEADER.ORG_ID   

       ,creation_date                = :HEADER.creation_date              

       ,…               

       ,attribute15                     = :HEADER.attribute15                         

       where return_fix_headers_id = :HEADER.return_fix_headers_id        

        if (sql%notfound) then   raise no_data_found ;

        end if ;                                                                      

END UPDATE_ROW; 

procedure DELETE_ROW is

begin  

    delete from TVSN_RETURN_FIX_HEADERS_ALL

    where return_fix_headers_id =  :HEADER.return_fix_headers_id;

     if (sql%notfound) then   raise no_data_found;

    end if;      

end DELETE_ROW;       

以上3段代码是很经典的插入,修改,删除语句。特点是每次操作完成之后都有一个检验过程,红色粗体语句。可以将这些代码放在数据库,pll文件,formprogram unit,甚至是直接写在trigger 中,从性能的角度出发可能放在数据库中更高效,综合维护方便等因素考虑,我建议写在formprogram unit中。

4.一个常见的错误

6.1

    有时候在输入一条新记录保存后再修改,会发生上图所示错误。错误的原因是ON-LOCK触发器检查到界面数据和后台数据不一致,所以提示用户。看到第3PROCEDURE INSERT_ROW代码::PARAMETER.G_ORG_ID系统向数据库中插入了一个参数的值,但是并没有保证界面上的字段:HEADER.ORG_ID有值或者:HEADER.ORG_ID的值与:PARAMETER.G_ORG_ID一致。

    一般导致这种错误的原因有:1界面字段未赋值使用了替代值存入数据库;2由于Item字段长度不够导致部分数据截断;3值列表与View字段内容不一致。建议在Lock Row字段中只锁定界面Block上的可见字段,在操作数据前保证Block字段与传入参数保持一致,最后就使用Block字段作为传入参数。

5.Master-Detail Block 的级联删除

     创建relation建立主从块关系时,可以设置级联删除属性,如图6.2所示,确定后主块会自动生成Pre-delete tigger代码为删除在数据库中对应的detail记录

                             图6.2

    如果在创建relation为设置级联删除,可以通过修改relation的属性Delete Record BehaviorCascading(如图6.3),新建主块Pre-delete trigger编写删除detial记录的代码,也能达到同样的效果。

6.3

   通过这种机制,oracle Form实现了前台界面清除数据和后台数据库删除数据的一致。有两点需要注意的是:

   1Detail Block的的数据源是View时,自动生成的Master Block Pre-delete trigger代码的删除对象是View,记得改成基表。

   当三层Master-Datail关系: C is child of B is child of A,当删除A块记录调用pre-delete代码删除B块记录,但是不会自动调用Bpre-delete代码删除C块记录,所以要将删除C块记录的语句写在Apre-delete中。

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值