zoukankan      html  css  js  c++  java
  • 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方法便可直接使用。如果内容有错误的地方请指正,如果有不懂得问题欢迎留言。

  • 相关阅读:
    Power BI 根据用户权限动态生成导航跳转目标
    Power BI Tooltips 增强功能
    Power BI refresh error “could not load file or assembly…provided impersonation level is invalid”
    SQL 错误代码 18456
    如何使用SQL Server Integration Services从多个Excel文件读取数据
    通过表格编辑器将现有表引入Power BI数据流
    Power BI 中动态增长的柱状图
    ambari2.7.3离线安装hdp3.1.0时,ambari-hdp-1.repo中baseurl无值
    ambari 安装 cannot download file mysql-connector-java from http://8080/resource/mysql-connector-java.jar
    洛谷P4180 [BJWC2010]严格次小生成树
  • 原文地址:https://www.cnblogs.com/zero-zyq/p/5413731.html
Copyright © 2011-2022 走看看