天天看點

在 EBS Form 查找界面點 "Find" 之後都發生了什麼?

      我一直對form 都感覺比較困惑, 特别是form 裡面的trigger, 像PRE-QUERY, POST-QUERY 一直都弄不清情況. 這個trigger 是什麼時候觸發的呢? 看名字就是在QUERY 之前或之後觸發的. 那麼QUERY 什麼呢? 搞不清楚.

     今天就看下代碼, 弄明白點了 "find" 之後做了什麼事情, 那些資料庫裡面的值怎麼到form 界面上去的.

     我們知道, 每一個form 上的資料塊都是綁定一個table 或者 view 的. 通常會綁定view. 像下面那樣:

在 EBS Form 查找界面點 "Find" 之後都發生了什麼?

     我們可以認為, 一個資料塊就是一個view. 而資料塊上的字段, 通常也和view 裡面的字段一一對應. 注意, 這裡說的是通常. 在我們剛開始學習做form 的時候, 選擇一個view, 比方說DEM_ORDER_V, 然後把view 裡面的字段一一對應于資料塊的字段, 這樣編譯運作的時候, 在form 界面菜單上 view -> query by -> run, 就可以直接做查詢的動作, 在form 界面上就會顯示出資料庫的記錄.

     這裡就做了一次QUERY 的動作, 查詢資料庫, 然後把記錄的值填到對應的field 裡面去.

     但是這樣的邏輯是簡單的, 沒有辦法應付EBS 複雜的業務邏輯. 是以在實際的做法中, 并沒有用這樣簡單直接的方式. 我們去看EBS 裡面的form, 資料庫上的字段和view 裡面的字段幾乎沒有對應關系. 似乎是兩個不相關連的東西, 隻是名字很像.

     這樣做的結果就是幾乎所有的行為都要自己寫代碼實作. 不能像上面那樣點下查詢, 然後所有的值自動顯示在界面上了. 由于缺少資料庫與界面字段的關聯, 即使查詢了資料庫, 也要手動把值複制給界面上的字段.

     我們以PO Receipts 界面為例, 看看點下"find" 都做了哪些事情.

1. 首先為了簡化問題, 我們這裡隻考慮RCVRCERC.fmb 這個form 隻有兩個資料塊 a) Find   b)RCV_TRANSACTION

在Find 界面上填寫好查詢條件後, 點一下"find", 這時會出發WHEN-BUTTON-PRESSED 這個trigger. 在這個trigger 裡面先調用APP_STANDARD.APP_VALIDATE (RECORD_SCOPE) 做驗證, 然後調用了FIND_BUTTON_CODE 這個方法. 

在這個方法裡面, 調用了RCV_FIND_C.FIND_BUTTON(‘WHEN-BUTTON-PRESSED‘,‘FIND‘,‘RCV_TRANSACTION‘) 這個過程. 

這時在RCVCOFND.pld 裡面定義的一個過程. 這個檔案是一個比較底層的檔案, Receipts form 從這個from 上繼承了很多, 也調用裡面的方法.

這個方法裡面有3 個參數, 第一個是trigger 名. 第二個是find block name, 第三個是navigation block name. 那麼調用這個過程會去到RCV_TRANSACTION 這個資料塊, 然後做查詢, 用下面的代碼來實作:

go_block(navigation block name);

do_key(‘EXECUTE_QUERY‘);

2. 那麼這時焦點就會跑到RCV_TRANSACTION 這個塊上去, 然後做查詢. 查詢什麼呢? 就是查詢這個資料塊所綁定的view.

在做查詢之前, 我們要在RCV_TRANSACTION 這個資料塊下面找到了PRE-QUERY 和 POST-QUERY 這兩個trigger. 這兩個是幹嘛的呢? 就是在做QUERY 之前給查詢做一些準備工作, 和查詢結束之後進行一些後續工作. PRE-QUERY 隻在查詢之前執行一次, 但是POST-QUERY 要在查詢之後觸發多次. 查詢到多少條記錄就出發多少次.

3. 現在來看PRE-QUERY 裡面做了什麼. 

先是調用了這個過程: analyze_search_criteria(l_rcv_view,   l_dest_query_pos,   l_src_type); 看名字能看出來是在做什麼... 分析查詢條件. 這3 個參數屬性都是OUT. 在這個過程裡面确定了查詢使用的view: l_rcv_view 是那個. 比如說, 如果我們做的是一個組織間轉移 inter org transfer, 那麼使用的view 就是RCV_ENTER_RECEIPTS_INTERNAL_V; 如果是ASN 接收的話,

使用的view 是RCV_ENTER_RECEIPTS_ASN_V; 使用哪個view 做查詢就是在這個過程裡面決定的. 決定标準是根據"Find" form 界面上填入的查詢條件. l_dest_query_pos 意思是使用的查詢方式, 有"from" 和 "where" 兩種取值可能. l_src_type 就是source type, 可能是INTERNAL, LCM, CUSTOMER, VENDOR, ALL 等等;

我們這裡考慮l_dest_query_pos = where 的情況. 

這裡面會用下面這個過程APP_QUERY.append(block_name, clause) 把 clause 加到前面block_name 後面, 作為查詢條件. 

4. 就這樣通過判斷find form 裡面填入的值, 給查詢的資料塊加入一個一個條件. 比如, 如果FIND.SOURCE_TYPE 的值是VENDOR, 加上的查詢條件就是: (RCV_ENTER_RECEIPTS_V.SOURCE_TYPE_CODE = ‘‘VENDOR‘‘ OR RCV_ENTER_RECEIPTS_V.SOURCE_TYPE_CODE = ‘‘ASN‘‘). 諸如此類.

5. PRE-QUERY 還做了一件事, 就是把find 界面上的值copy 給RCV_TRANSACTION 對應的字段. 但是這些不是作為查詢條件來的.

6. 就這樣在PRE-QUERY 裡面确定了查詢使用哪個view, 并且确定了查詢條件. 然後就是做查詢的動作. 查詢是從前面的RCV_ENTER_RECEIPTS_INTERNAL_V 和RCV_TRANSACTION 綁定的view RCV_ENTER_RECEIPTS_V 兩個view 裡面查出結果來. 當查詢結束後, 就會執行POST-QUERY 這個trigger.

7. 之前我們說過, 由于RCV_TRANSACTION 這個資料塊上的字段和view 裡面的字段是沒有綁定關系的, 是以查詢出來的結果并不會自動指派給界面上的字段. 需要在POST-QUERY 裡面手動指派. 是以這個trigger 主要就是做的指派的工作. 這個裡面有大量的代碼, 格式很單一:

if (criteria ) then select a into b from table where .. copy (b , ‘RCV_TRANSACTION.field‘);

也就是根據某個條件從資料庫查出某個值, 指派給資料庫的字段. 是以這個裡面出現了大量select 語句和copy 語句.

8. 在POST-QUERY 裡面也調用了非常多的資料庫過程, 這些過程寫在 pls  檔案中. 這裡沒有去深究這許多過程有哪些功能, 但能從調用的結果上看出來, 這裡面是做了一些邏輯判斷和計算的. 例如v_secondary_quantity  := inv_convert.inv_um_convert

9. 另外在這個trigger 的最後會set 字段的屬性, 例如set_item_property: item_is_valid, 就是讓字段驗證屬性為真.

10. 到這裡為止, query 的動作就做完了, 通過PRE-QUERY 設定查詢條件, POST-QUERY 給界面字段指派. 要注意的是, 如果查詢出來有兩條記錄的話, 那麼POST-QUERY 會執行兩次. 為啥要執行兩次呢? 因為界面上兩條記錄的字段是不一樣的, 需要根據不同的條件指派, 比如兩條記錄的id 不一樣, 就要用這個id 分别查出某個字段的值在指派.

11. 到這裡為止, 上面的RCV_FIND_C.FIND_BUTTON(‘WHEN-BUTTON-PRESSED‘,‘FIND‘,‘RCV_TRANSACTION‘) 這個過程就執行完了. 在此之後又執行了一下過程, 但是已經更查詢的關系不大了, 主要是跳到某個視窗, 設定屬性等等. 至此, WHEN-BUTTON-PRESSED 這個trigger 就全部執行完畢了. 查詢的結果就已經在界面上顯示出來了. 

12. 在焦點跳入RCV_TRANSACTION 資料塊的時候, 又會出發WHEN-NEW-RECORD-INSTANCE 等等trigger, 但這是後事了, 這裡就不讨論了;

     總結: 這樣的做法顯得非常複雜而且需要寫很多代碼, 但是優點也是比較明顯的, 這對于所有的字段都有比較精确的控制. 這對于實作複雜的業務邏輯是必須的. 

     代碼中有許多built-in 的代碼, 可以在form builder 裡面找看看是怎麼用的. 幫助很大.

     注: 這是我看着代碼寫出來的, 如果裡面有錯誤的地方, 希望大家能夠指出來, 共同進步.

繼續閱讀