看本篇之前可以相应阅读以下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方法便可直接使用。如果内容有错误的地方请指正,如果有不懂得问题欢迎留言。

作者:zero

博客地址:http://www.cnblogs.com/zero-zyq/

本文欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接

个人下载了一些相关学习的PDF文件,如果需要下载请访问百度云点击此处访问 密码:jhuy

如果文章的内容对你有帮助,欢迎点赞~

为方便手机端查看博客,现正在将博客迁移至微信公众号:Salesforce零基础学习,欢迎各位关注。

【转】【Salesforce】salesforce 零基础学习(十七)Trigger用法的更多相关文章

  1. salesforce lightning零基础学习(十七) 实现上传 Excel解析其内容

    本篇参考: https://developer.mozilla.org/zh-CN/docs/Web/API/FileReader https://github.com/SheetJS/sheetjs ...

  2. salesforce lightning零基础学习(十五) 公用组件之 获取表字段的Picklist(多语言)

    此篇参考:salesforce 零基础学习(六十二)获取sObject中类型为Picklist的field values(含record type) 我们在lightning中在前台会经常碰到获取pi ...

  3. salesforce lightning零基础学习(二) lightning 知识简单介绍----lightning事件驱动模型

    看此篇博客前或者后,看一下trailhead可以加深印象以及理解的更好:https://trailhead.salesforce.com/modules/lex_dev_lc_basics 做过cla ...

  4. salesforce lightning零基础学习(一) lightning简单介绍以及org开启lightning

    lightning对于开发salesforce人员来说并不陌生,即使没有做过lightning开发,这个名字肯定也是耳熟能详.原来的博客基本都是基于classic基于配置以及开发,后期博客会以ligh ...

  5. salesforce lightning零基础学习(三) 表达式的!(绑定表达式)与 #(非绑定表达式)

    在salesforce的classic中,我们使用{!expresion}在前台页面展示信息,在lightning中,上一篇我们也提及了,如果展示attribute的值,可以使用{!v.expresi ...

  6. salesforce lightning零基础学习(十三) 自定义Lookup组件(Single & Multiple)

    上一篇简单的介绍了自定义的Lookup单选的组件,功能为通过引用组件Attribute传递相关的sObject Name,捕捉用户输入的信息,从而实现搜索的功能. 我们做项目的时候,可能要从多个表中获 ...

  7. salesforce lightning零基础学习(十一) Aura框架下APP构造实现

    前面的一些lightning文章讲述了aura的基础知识,aura封装的常用js以及aura下的事件处理.本篇通过官方的一个superbadge来实现一个single APP的实现. superbad ...

  8. salesforce lightning零基础学习(七) 列表展示数据时两种自定义编辑页面

    上一篇Lightning内容描述的是LDS,通过LDS可以很方便的实例化一个对象的数据信息.当我们通过列表展示数据需要编辑时,我们常使用两种方式去处理编辑页面:Pop Up Window弹出修改详情以 ...

  9. salesforce lightning零基础学习(十) Aura Js 浅谈三: $A、Action、Util篇

    前两篇分别介绍了Component类以及Event类,此篇将会说一下 $A , Action以及 Util.  一. Action Action类通常用于和apex后台交互,设置参数,调用后台以及对结 ...

  10. salesforce lightning零基础学习(八) Aura Js 浅谈一: Component篇

    我们在开发lightning的时候,常常会在controller.js中写 component.get('v.label'), component.set('v.label','xxValue'); ...

随机推荐

  1. NodeJS包管理器之Yarn

    一.安装yarn 首选必须先安装好NodeJS,之后可以去yarn官网下载mis安装程序安装.由于NodeJS自带了一个包管理器npm,所以安装yarn更简单的方法是直接使用npm install - ...

  2. Android之WebRTC介绍

    参考自:Introduction to WebRTC on AndroidAndroid之WebRTC介绍 WebRTC被誉为是web长期开源开发的一个新启元,是近年来web开发的最重要创新.WebR ...

  3. Spring Boot接入 apollo 后启动 dubbo 报错

    原文地址:https://xobo.org/spring-boot-apollo-dubbo-xml-error/ 某Spring Boot项目接入 apollo 后启动 dubbo 报错Caused ...

  4. Spring MVC -- Spring Tool Suite和Maven(安装Tomcat、JDK)

    Spring提供了自己的集成开发环境(IDE),称为Spring Tool Suite(STS),它可能是构建Spring应用程序的最佳IDE了.STS捆绑了Maven作为其默认依赖管理工具,因此不需 ...

  5. 使用垃圾桶机制防止rm -rf误删文件

    偶然看到一个比较好用的工具Trash-Cli.一个类似垃圾桶的机制,可以恢复文件.试了一下,感觉还行 (1)下载安装: https://github.com/andreafrancia/trash-c ...

  6. springboot redis 示例代码

    pom.xml <?xml version="1.0" encoding="UTF-8"?> <project xmlns="htt ...

  7. 【MongoDB学习之六】MongoDB集群

    环境 MongoDB 4.0 CentOS 6.5_x64 一.主从复制-Master-Slave这种模式已不再推荐使用了. 二.副本集-Replica Set(用的多)副本集其实一种互为主从的关系, ...

  8. springboot自定义类@Resource注入为null的问题

    最近用spring boot ,在controller外面即自定义的类里报错 java.lang.NullPointerException debug了下发现@Resource注入为null 查了不少 ...

  9. Git - ignore过滤文件

    Git - ignore 官网:https://git-scm.com/docs/gitignore 今天在初始化仓库的时候,考虑到如何过滤不需要的文件进入版本控制系统.所以去查阅了一番官方文档. 想 ...

  10. Mac多SSH Key配置

    多SSH key配置 工作的时候碰到SSH配置的问题,就是公司用的是gittea的仓库,而本人的github平常也要使用,这个时候就需要配置不同的SSH key了.将同一个公钥分配配置给github和 ...