看本篇之前可以相應(yīng)閱讀以下Trigger相關(guān)文章:
- https://developer.salesforce.com/page/Trigger_Frameworks_and_Apex_Trigger_Best_Practices
- http://chrisaldridge.com/triggers/lightweight-apex-trigger-framework/
- 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方法便可直接使用。