salesforce 零基礎學習(十七)Trigger用法


看本篇之前可以相應閱讀以下Trigger相關文章:

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應用特別簡單,所以沒有列出來單獨講解,和群里大神問問題以后,發現還是很有必要將Trigger單獨寫出來一篇,讓新手更好的了解Trigger。

 一.Trigger介紹

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

有兩種類型的trigger:

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

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

eg:trigger GoodsTrigger on Goods__c (before delete, before update) {}:聲明一個trigger針對Goods__c這個Object,當執行delete,update操作以前執行此trigger。

trigger可以有以下的執行類別:before insert,before update,before delete,after insert,after update,after delete,after undelete.

注意:trigger代碼塊中不能包含static關鍵字。

Trigger類中封裝了很多的上下文的變量,這些變量在開發中經常用到。

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

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

  • new只適用於執行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內部塊中寫業務邏輯;第二種為通過Handler對trigger進行封裝。以下是兩種方式的介紹.

1.直接在trigger內部塊中寫代碼。代碼描述如下(業務邏輯不重要,隨便寫的):

  1)Goods__c與GoodsSign__c存在LookUp關系;

  2)當對Goods__c進行刪除操作時,級聯刪除GoodsSign__c表關聯的數據;

  3)當執行update操作時,Goods__c表數據的GoodsName__c字段內容當月發生改變時,GoodsSign__c的GoodsNameSign__c標記成true.

 1 trigger GoodsTrigger on Goods__c (before delete, before update) {
 2     
 3     List<Goods__c> goodsListOld = trigger.old;
 4     Id goodsSignId;
 5     Goods__c goodsOld = goodsListOld.get(0);
 6     Datetime lastModifyDatetimeOld;
 7     Datetime lastModifyDatetimeNew;
 8     GoodsSign__c goodsSign = new GoodsSign__c();
 9     if(trigger.IsDelete) {
10         //delete cascade
11         goodsSignId = goodsOld.Id;
12         List<GoodsSign__c> goodsSignDeleteList = [select Id,Name from GoodsSign__c where Id = :goodsSignId];
13         try {
14             if(goodsSignDeleteList.size()>0) {
15               delete goodsSignDeleteList;
16             }
17         }catch(Exception e) {
18             //TODO error operation
19         }         
20     } else if(trigger.IsUpdate){
21         List<Goods__c> goodsListNew = trigger.new;
22         Goods__c goodsNew = goodsListNew.get(0);
23         //update operation
24         /*
25          * when first update the record,the system didn't have old.LastModifiedDate
26          * then use CreatedDate instead of LastModifiedDate
27         */
28         lastModifyDatetimeOld = goodsOld.LastModifiedDate == null ? goodsOld.CreatedDate : goodsOld.LastModifiedDate;
29         lastModifyDatetimeNew = goodsNew.LastModifiedDate;
30         goodsSignId = goodsNew.Id;
31         List<GoodsSign__c> goodsSignAlreadyExistsList = [select CreatedById, CreatedDate, IsDeleted, GoodsSignId__c, GoodsNameSign__c, Name, LastModifiedById, LastModifiedDate, OwnerId, Id, SystemModstamp from GoodsSign__c where GoodsSignId__c = :goodsSignId];
32         if(goodsSignAlreadyExistsList.size()>0) {
33             goodsSign = goodsSignAlreadyExistsList.get(0);
34         } else {
35             goodsSign.GoodsSignId__c = goodsSignId;
36         }
37         //---------GoodsNameSign----------//
38         if(lastModifyDatetimeNew.year() == lastModifyDatetimeOld.year() && lastModifyDatetimeNew.monthGmt() == lastModifyDatetimeOld.monthGmt()) {
39             String goodsNameNew = goodsNew.GoodsName__c;
40             if(!goodsNameNew.equals(goodsOld.GoodsName__c)) {
41                 goodsSign.GoodsNameSign__c = true;
42             } else {
43                 goodsSign.GoodsNameSign__c = false;
44             }
45         } else {
46             goodsSign.GoodsNameSign__c = false;
47         }
48         
49         try {
50             upsert goodsSign;
51         }catch(Exception e) {
52             
53         }
54         
55     }
56    
57 }

2.通過Handler方式.

通過Handler方式可以將每個Object創建其自身的Handler,將trigger業務邏輯寫在自身的Handler里面,並通過Factory實例化,達到更好的可擴展性以及可讀性,操作步驟如下所示:

  1)創建TriggerHandler父類

 1 public abstract class TriggerHandler {
 2     /*
 3         Trigger中,在運行時封裝了new,newMap,old,oldMap變量
 4         其中,new和old返回類型為List<sObject>
 5         newMap和oldMap返回類型為Map<Id,sObject>
 6     */
 7     
 8     protected Map<Id,sObject> oldMap{get;set;}
 9     
10     protected Map<Id,sObject> newMap{get;set;}
11     
12     protected List<sObject> listNew{get;set;}
13     
14     protected List<sObject> listOld{get;set;}
15     
16     /*
17         封裝trigger應該注意以下幾點:
18         1.trigger.new只能用在insert和update時,且trigger必須是before;
19         2.trigger.old只能用在update和delete時;
20         3.trigger.newMap只能用在before update,after insert和after update時;
21         4.trigger.oldMap只能用在update和delete時.
22     */
23     public interface MyTrigger {
24     
25         void beforeInsert(SObject currentObject);
26     
27         void beforeUpdate(SObject oldSobject, SObject currentObject);
28     
29         void beforeDelete(SObject currentObject);
30     
31         void afterInsert(SObject currentObject);
32     
33         void afterUpdate(SObject oldSobject, SObject currentObject);
34     
35         void afterDelete(SObject currentObject);
36         
37         Boolean skipExecution();
38   }
39 }

  2)創建相關對象的Handler,繼承TriggerHandler並實現其MyTrigger接口,並實現相關方法。

 1 public class GoodsHandler extends TriggerHandler implements TriggerHandler.MyTrigger {
 2     
 3     public GoodsHandler() {
 4         // TODO Construcion
 5     }
 6     
 7     public void beforeInsert(SObject currentObject) {
 8         // TODO beforeInsert
 9     } 
10     public void afterInsert(SObject currentObject) {
11         // TODO afterInsert
12     }
13     
14     public void beforeUpdate(SObject oldSobject, SObject currentObject) {
15         // TODO beforeUpdate
16     }
17     
18     public void beforeDelete(SObject currentObject) {
19         //TODO beforeDelete
20     }
21     
22     
23     
24     public void afterUpdate(SObject oldSobject, SObject currentObject) {
25         
26     }
27     
28     public void afterDelete(SObject currentObject) {
29         
30     }
31     
32     public Boolean skipExecution() {
33         return false;
34     }
35 }

  3)創建TriggerFactory,此方法用於實例化Trigger的Handler並執行相應的before或者after操作,其中MyException為自定義異常類。

1 public class MyException extends Exception {
2     
3 }
 1 public class TriggerFactory {
 2     /*
 3         實例化Handler,如果不跳過executeTrigger情況下,自動執行Trigger
 4     */
 5     public static void instanceHandler(Schema.SObjectType objectToken) {
 6         TriggerHandler.MyTrigger myTriggerHandler = getTriggerByObjectToken(objectToken);
 7         if(myTriggerHandler == null) {
 8             throw new MyException('無此object token的trigger');
 9         }
10         if(!myTriggerHandler.skipExecution()) {
11             executeTrigger(myTriggerHandler);
12         }
13     }
14     
15     /*
16         執行trigger應該注意以下幾點:
17         1.trigger.new只能用在insert和update時,且trigger必須是before;
18         2.trigger.old只能用在update和delete時;
19         3.trigger.newMap只能用在before update,after insert和after update時;
20         4.trigger.oldMap只能用在update和delete時.
21     */
22     public static void executeTrigger(TriggerHandler.MyTrigger myTriggerHandler) {
23         //trigger分成isBefore以及isAfter
24         if(Trigger.isBefore) {
25             if(Trigger.isInsert) {
26                 for (SObject currentObject : Trigger.new)
27                 {
28                     myTriggerHandler.beforeInsert(currentObject);
29                 } 
30             }else if(Trigger.isUpdate) {
31                 for (SObject oldObject : Trigger.old)
32                 {
33                     myTriggerHandler.beforeUpdate(oldObject, Trigger.newMap.get(oldObject.Id));
34                 }
35             }else if(Trigger.isDelete) {
36                 for (SObject currentObject : Trigger.old)
37                 {
38                     myTriggerHandler.beforeDelete(currentObject);
39                 }
40             }
41         } else {//isAfter
42              if (Trigger.isInsert) {
43                 for (SObject currentObject : Trigger.new) {
44                     myTriggerHandler.afterInsert(currentObject);
45                 }   
46              } else if (Trigger.isUpdate) {
47                 for (SObject oldObject : Trigger.old) {
48                     myTriggerHandler.afterUpdate(oldObject, Trigger.newMap.get(oldObject.Id));
49                 }   
50              } else if (Trigger.isDelete){
51                 for (SObject currentObject : Trigger.old) {
52                     myTriggerHandler.afterDelete(currentObject);
53                 }   
54              }
55         }
56     }
57     
58     
59     /*
60         此方法用於返回具體某個object的trigger,如果添加一個object的trigger,在此方法添加相應的匹配處理,
61         同時此object的Handler必須繼承TriggerHandler以及實現TriggerHandler.MyTrigger
62         每個Object的Object Token不同,所以使用Token作為參數更加便捷
63     */
64     public static TriggerHandler.MyTrigger getTriggerByObjectToken(Schema.SObjectType objectToken) {
65         if(objectToken == Goods__c.sObjectType) {
66             return new GoodsHandler();
67         }
68         // TODO  有其他Object需要使用trigger可以繼承TriggerHandler實現其中MyTrigger然后在此處配置
69         return null;
70     }
71 }

  4)相應Object的trigger調用Factory的實例化方法

1 trigger GoodsTrigger on Goods__c (before delete, before update) {
2   TriggerFactory.instanceHandler(Goods__c.sObjectType);
3 }

  當Goods__c字段進行delete或者update操作時,save以前,會自動觸發GoodsTrigger,GoodsTrigger會執行TriggerFactory的instanceHandler方法,此方法會調用執行instanceHandler以及executeTrigger函數,從而最終將Goods__c表trigger業務邏輯由GoodsHandler類處理。

總結:如果業務相對簡單,可以采用第一種方式,開發效率高;如果業務相對復雜,第二種方式可以在相應的Handler模塊更加明了的書寫業務邏輯,方便后期維護以及有更好的可讀性,有相關需求的童鞋可以copy代碼,並修改其中TriggerFactory的getTriggerByObjectToken方法便可直接使用。如果內容有錯誤的地方請指正,如果有不懂得問題歡迎留言。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM