[轉載] Dynamics 365 Business Central開發實戰-4:Publishers and Subscribers

<< 以下為轉載文章。。。>>

2019/6/10
在上一篇文章中,我們透過新增 Codeunit 50000 和 function “ TransferExpenseCodetToPurchLineFromGL” 來完這規格第五項。我們來看看系統執行時到底是怎麼跑這些程式碼的:

1. 程式走進了 Table 39 的 “CopyFromGLAccount” function 中
2. 程式走進了 OnAfterAssignGLAccountValues() 中
3. 發現 OnAfterAssignGLAccountValues() 是一個 IntegrationEvent (或是說 Publisher),於是尋找其 Subscribers
4. 發現在 Codeunit 50000 中的 TransferExpenseCodeToPurchLineFromGL() 是 OnAfterAssignGLAccountValues() 的 Subscriber,所以執行其程式碼。
5. 執行完 CopyFromGLAccount() 的所有程式碼,所以結束了 CASE 語句的區塊。繼續執行 283 行以後的程式碼



我們發現,系統是透過一個 Publisher-Subscriber 的神奇機制,將 Table 39 的 OnAfterAssignGLAccountValues() 和 Codeunit 50000 的 TransferExpenseCodeToPurchLineFromGL() 連結在一起的。加上因為 OnAfterAssignGLAccountValues(Rec, GLAcc) 傳入了兩筆資料:Rec 即代表 Purchase Line 的資料,GLAcc 代表 G/L Account 的資料,所以我們可以在 TransferExpenseCodeToPurchLineFromGL() 去利用 G/L Account 的欄位對 Purchase Line 的欄位進行賦值。至此,原本應該要寫在 Table 39 的程式碼也可以移到 Codeunit 50000 了,達成不更動標準物件的開發最佳實務 (Best Practice)。
有關 Publisher 和 Subscriber 的機制,可以想像成今天你在 Facebook 上面發佈 (Publish) 了一篇文:”留言我愛大珍奶和你要的甜度冰塊就免費送你60嵐的大珍奶!”。於是有幾個不知好歹的朋友就留言 “我愛大珍奶,半糖少冰”,成為了這篇文章的 Subscriber。隔天,你買完了這些 Subscribers 要喝的大珍奶後,就在同一篇文章留言:”大珍奶買好了,來我家自取”,而這些 Subscribers 都會收到通知。另外,Subscriber 所註明的 “半糖少冰” 也會影響到你買的飲料細節。
而這裡程式碼的運作方式也是相同的。微軟的 Business Central 核心開發人員很貼心的設想在 CopyFromGLAccount() 裡面一定之後會有客製的需求,就像是我們現在新增欄位並帶入值一樣。於是,他在 CopyFromGLAccount() 的最後一行加上了一個 OnAfterAssignGLAccountValues() 的 Publisher function。這個函式就像剛在 Facebook 發佈的文章一樣,沒有任何留言,但昭告大家有這件事。之後,開發者就可以在客製的 Codeunit 中,去寫 function 訂閱 (Subscribe) 該 Publisher Function。而當程式執行到 OnAfterAssignGLAccountValues(),他就會尋找並執行他的 Subscriber,並執行 Subscriber 裡面的程式碼。有點像是你看有誰留言,並跟據他們的甜度冰塊去買珍奶一樣。
上面的比喻傳達了在這個架構下,客製的自由度是受限制的。今天如果你沒有發佈貼文,那你的朋友也沒有免費飲料喝,這體現了微軟必須在很多地方都預想系統未來會怎麼被客製,並事先埋下 Publisher function。而程式設計師用這個架構在客製時也無法接觸到原先物件所有的 Global Variables。以上面的例子來說,就只能使用 “Purchase Line” (Rec) 和 “G/L Account” (GLAcc) 而已。這也像是我們的項閱者只能指明半糖少冰,卻不能把珍奶換成雞排。
這個架構也考驗著程式設計師的功力。程式設計師若要遵照開發的最佳實務,已經無法像以前一樣在哪個地方亂客製一通都好,反正只要達成需求即可。取而代之的是,他必須非常熟悉標準的程式碼,並且習慣 trace codes,找到最適合插入程式碼的地方 / Event,並建立新物件寫 Subscriber functions。當然,有人會問說如果真的找不到適當的標準 Publisher function 怎麼辦。筆者認為,在未來 Business Central 更加成熟,標準的 Publisher functions 也更多的時候,這個情況應該要很少成立才對。如果真的發生,請先想想程式是否還有其它種寫法、作業流程是否合理、是否是規格的不合理照成程式開發上的 Anti-pattern。



打鐵趁熱,我們現在把規格第六項做掉:
6. 如果使用者在 Purchase Line 中修改 Quantity,”Expense Code” 的值要能被清除掉
分析:VALIDATE “Quantity” 的欄位
有了 Publisher-Subscriber 的概念後,我們知道 Purchase Line 中的 Quantity — OnValidate() 本身就是一個事件,可將它直接認定為一個 Publisher。於是,我們在 Codeunit 50000 新增一個函式 “OnAfterValidatePOQuantity”,並且設定其 properties 如下:

Properties of subscriber function “OnAfterValidatePOQuantity”

其實程式碼如下圖,大意就是 “如果修改之前的數量不為零,且修改後的數量不等於修改前的數量,就將 Purchase Line 的 “Expense Code” 設為空白。

Codes in function “OnAfterValidatePOQuantity”

我們成功完成了需求第一項到第六項。下一篇文章,我會帶大家完成比較難、牽涉到過帳程式的需求七、八。但基本上,在開發中的概念都還是一樣的。Stay tuned!



*********************************************************************************

<< 以上文章,經作者 Ray 同意,轉載自 https://medium.com/@nturay0321 >>


留言