trigger的使用

看本篇之前可以相應(yīng)閱讀以下Trigger相關(guān)文章:

  1. https://developer.salesforce.com/page/Trigger_Frameworks_and_Apex_Trigger_Best_Practices
  2. http://chrisaldridge.com/triggers/lightweight-apex-trigger-framework/
  3. http://www.sfdc99.com/2015/01/19/the-one-trigger-per-object-design-pattern/

以前以為salesforce中Trigger應(yīng)用特別簡單,所以沒有列出來單獨講解,總結(jié)問題以后,發(fā)現(xiàn)還是很有必要將Trigger單獨寫出來一篇,讓新手更好的了解Trigger。

一.Trigger介紹

Trigger在salesforce記錄更改以前或者以后自動執(zhí)行,可以執(zhí)行以下幾種情況:insert,update,delete,merge,upsert,undelete,一個trigger可以同時處理200條records,所以后面所講的new和old變量的返回類型為List類型。
有兩種類型的trigger:

  • Before trigger通常用于在他們被保存在數(shù)據(jù)庫以前更新或者校驗數(shù)據(jù);
  • After trigger通常用于保存后訪問系統(tǒng)的字段(Id等).

trigger設(shè)計的思想為'One Trigger per Object',這種設(shè)計的好處詳情查看上方第三個鏈接。所以一個Trigger可以同時設(shè)定很多種自動執(zhí)行的觸發(fā)器情況。eg:

    trigger GoodsTrigger on Goods__c (before delete, before update) {}

聲明一個trigger針對Goods__c這個Object,當執(zhí)行delete,update操作以前執(zhí)行此trigger。
  trigger可以有以下的執(zhí)行類別:before insert,before update,before delete,after insert,after update,after delete,after undelete.
  注意:trigger代碼塊中不能包含static關(guān)鍵字。
  Trigger類中封裝了很多的上下文的變量,這些變量在開發(fā)中經(jīng)常用到。

  • isExecuting:當前Apex代碼的上下文環(huán)境為trigger環(huán)境,而不是VF等則返回true,否則返回false;
  • isInsert:當前操作是否為正在執(zhí)行添加操作,是返回true,否則返回false;
  • isUpdate:當前操作是否為正在執(zhí)行修改操作,是返回true,否則返回false;
  • isDelete:當前操作是否為正在執(zhí)行刪除操作,是返回true,否則返回false;
  • isBefore:當前操作是否為在save以前操作,是返回true,否則返回false;
  • isAfter:當前操作是否為在save以后操作,是返回true,否則返回false;
  • isUndelete:當前操作是否為在回收箱中回復(fù)數(shù)據(jù)以后操作,是返回true,否則返回false;
  • new:返回sObject的記錄的最新的數(shù)據(jù)的列表;
  • newMap:返回一個ID映射到最新的數(shù)據(jù)列表的Map集合;
  • old:返回sObject的記錄修改以前的數(shù)據(jù)的列表;
  • oldMap:返回一個ID映射到修改以前的數(shù)據(jù)列表的Map集合;
  • size:在觸發(fā)器中調(diào)用的數(shù)據(jù)總數(shù),包括new和old。

這里主要描述一下new,newMap,old以及oldMap,因為他們有使用限制。

  • new只適用于執(zhí)行insert和update的trigger操作時并且類型為before的時候,才可以使用new返回列表;
  • newMap只適用于before update,after insert以及after update的trigger操作時,才可以使用newMap返回map集合;
  • old以及oldMap只適用于update和delete操作時,才可以使用old以及oldMap。

二.Trigger的使用

目前本人使用trigger主要有兩種方式:第一種為直接使用trigger,在trigger內(nèi)部塊中寫業(yè)務(wù)邏輯;第二種為通過Handler對trigger進行封裝。以下是兩種方式的介紹.
  1. 直接在trigger內(nèi)部塊中寫代碼。代碼描述為(在before和after trigger時輸出debug信息):

     trigger GoodsTrigger on Goods__c (before delete, before update) { 
        if(trigger.isBefore) {
          System.debug('=======before trigger========');
        } else {
          System.debug('=======after trigger========');
        }
    }

2. 通過Handler方式.通過Handler方式可以將每個Object創(chuàng)建其自身的Handler,將trigger業(yè)務(wù)邏輯寫在自身的Handler里面,并通過Factory實例化,達到更好的可擴展性以及可讀性,操作步驟如下所示:

  • 創(chuàng)建TriggerHandler父類

      public abstract class TriggerHandler {   
        /* Trigger中,在運行時封裝了new,newMap,old,oldMap變量
        * 其中,new和old返回類型為ListnewMap和oldMap返回類型為Map
        */        
        protected MapoldMap{get;set;}       
        protected MapnewMap{get;set;}       
        protected ListlistNew{get;set;}        
        protected ListlistOld{get;set;}
        /*
        *  封裝trigger應(yīng)該注意以下幾點:
        * 1.trigger.new只能用在insert和update時,且trigger必須是before;
        * 2.trigger.old只能用在update和delete時;
        * 3.trigger.newMap只能用在before update,after insert和after update時;
        * 4.trigger.oldMap只能用在update和delete時.
        */
        public interface MyTrigger {
          void beforeInsert(SObject currentObject);
          void beforeUpdate(SObject oldSobject, SObject currentObject);
          void beforeDelete(SObject currentObject);
          void afterInsert(SObject currentObject);
          void afterUpdate(SObject oldSobject, SObject currentObject);
          void afterDelete(SObject currentObject);
          Boolean skipExecution();
        }
      }
    
  • 創(chuàng)建相關(guān)對象的Handler,繼承TriggerHandler并實現(xiàn)其MyTrigger接口,并實現(xiàn)相關(guān)方法。
    public class GoodsHandler extends TriggerHandler implements TriggerHandler.MyTrigger {
    public GoodsHandler() {
    // TODO Construcion
    }
    public void beforeInsert(SObject currentObject) {
    // TODO beforeInsert
    }
    public void afterInsert(SObject currentObject) {
    // TODO afterInsert
    }
    public void beforeUpdate(SObject oldSobject, SObject currentObject) {
    // TODO beforeUpdate
    }
    public void beforeDelete(SObject currentObject) {
    //TODO beforeDelete
    }
    public void afterUpdate(SObject oldSobject, SObject currentObject) {
    }
    public void afterDelete(SObject currentObject) {
    }
    public Boolean skipExecution() {
    return false;
    }
    }

  • 創(chuàng)建TriggerFactory,此方法用于實例化Trigger的Handler并執(zhí)行相應(yīng)的before或者after操作,其中MyException為自定義異常類。
    public classMyExceptionextendsException {
    }

      public class TriggerFactory {
        /*
         * 實例化Handler,如果不跳過executeTrigger情況下,自動執(zhí)行Trigger
        */
        public static void instanceHandler(Schema.SObjectType objectToken) {
          TriggerHandler.MyTrigger myTriggerHandler = getTriggerByObjectToken(objectToken);
          if(myTriggerHandler == null) {
            throw new MyException('無此object token的trigger');
          }
          if(!myTriggerHandler.skipExecution()) {
            executeTrigger(myTriggerHandler);
          }
        }
        /*
         * 執(zhí)行trigger應(yīng)該注意以下幾點:
         * 1.trigger.new只能用在insert和update時,且trigger必須是before;
         * 2.trigger.old只能用在update和delete時;
         * 3.trigger.newMap只能用在before update,after insert和after update時;
         * 4.trigger.oldMap只能用在update和delete時.
        */
        public static void executeTrigger(TriggerHandler.MyTrigger myTriggerHandler) {
          //trigger分成isBefore以及isAfter
          if(Trigger.isBefore) {
            if(Trigger.isInsert) {
              for (SObject currentObject : Trigger.new) {
                myTriggerHandler.beforeInsert(currentObject);
              }
            }else if(Trigger.isUpdate) {
              for (SObject oldObject : Trigger.old) {
                myTriggerHandler.beforeUpdate(oldObject, Trigger.newMap.get(oldObject.Id));
              }
            }else if(Trigger.isDelete) {
              for (SObject currentObject : Trigger.old) {
                myTriggerHandler.beforeDelete(currentObject);
              }
            }
          } else {//isAfter
            if (Trigger.isInsert) {
              for (SObject currentObject : Trigger.new) {
                myTriggerHandler.afterInsert(currentObject);
              }
            } else if (Trigger.isUpdate) {
              for (SObject oldObject : Trigger.old) {
                myTriggerHandler.afterUpdate(oldObject, Trigger.newMap.get(oldObject.Id));
              }
            } else if (Trigger.isDelete){
              for (SObject currentObject : Trigger.old) {
                myTriggerHandler.afterDelete(currentObject);
              }
            }
          }
        }
        /*
        * 此方法用于返回具體某個object的trigger,如果添加一個object的trigger,在此方法添加相
        * 應(yīng)的匹配處理,同時此object的Handler必須繼承TriggerHandler以及實現(xiàn)TriggerHandler.
        * MyTrigger每個Object的Object Token不同,所以使用Token作為參數(shù)更加便捷
        * */
        public static TriggerHandler.MyTrigger getTriggerByObjectToken(Schema.SObjectType objectToken) {
          if(objectToken == Goods__c.sObjectType) {
            return new GoodsHandler();
          }
          // TODO  有其他Object需要使用trigger可以繼承TriggerHandler實現(xiàn)其中MyTrigger然后在此處配置
          return null;
        }
      }
    
  • 相應(yīng)Object的trigger調(diào)用Factory的實例化方法
    trigger GoodsTrigger on Goods__c (before delete, before update) {
    TriggerFactory.instanceHandler(Goods__c.sObjectType);
    }

當Goods__c字段進行delete或者update操作時,save以前,會自動觸發(fā)GoodsTrigger,GoodsTrigger會執(zhí)行TriggerFactory的instanceHandler方法,此方法會調(diào)用執(zhí)行instanceHandler以及executeTrigger函數(shù),從而最終將Goods__c表trigger業(yè)務(wù)邏輯由GoodsHandler類處理。
   ** 總結(jié) **:如果業(yè)務(wù)相對簡單,可以采用第一種方式,開發(fā)效率高;如果業(yè)務(wù)相對復(fù)雜,第二種方式可以在相應(yīng)的Handler模塊更加明了的書寫業(yè)務(wù)邏輯,方便后期維護以及有更好的可讀性,有相關(guān)需求的童鞋可以copy代碼,并修改其中TriggerFactory的getTriggerByObjectToken方法便可直接使用。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 229,836評論 6 540
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 99,275評論 3 428
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 177,904評論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,633評論 1 317
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,368評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 55,736評論 1 328
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,740評論 3 446
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 42,919評論 0 289
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 49,481評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 41,235評論 3 358
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,427評論 1 374
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,968評論 5 363
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 44,656評論 3 348
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,055評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,348評論 1 294
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,160評論 3 398
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,380評論 2 379

推薦閱讀更多精彩內(nèi)容

  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 134,818評論 18 139
  • 1. Java基礎(chǔ)部分 基礎(chǔ)部分的順序:基本語法,類相關(guān)的語法,內(nèi)部類的語法,繼承相關(guān)的語法,異常的語法,線程的語...
    子非魚_t_閱讀 31,733評論 18 399
  • 一. Java基礎(chǔ)部分.................................................
    wy_sure閱讀 3,829評論 0 11
  • 多態(tài) 任何域的訪問操作都將有編譯器解析,如果某個方法是靜態(tài)的,它的行為就不具有多態(tài)性 java默認對象的銷毀順序與...
    yueyue_projects閱讀 971評論 0 1
  • 風(fēng)電場總裝機為什么是49.5MW不是50MW 國家發(fā)改委有文件規(guī)定,總裝機容量高于50MW的風(fēng)電投資項目需要交由國...
    不撈魚的貓閱讀 161評論 0 0