Apex Triggers

Apex 触发器(Apex Triggers)是一种特殊的 Apex 类。它的主要作用是在一条记录被插入、修改、删除之前或之后自动执行一系列的操作。每一个 Trigger 类必须对应一种对象。

Trigger 的语法和普通的 Apex 类一样。

Salesforce 建议开发者在创建 Trigger 之前,考虑一下相同的操作可否通过 Salesforce 的设置界面中的功能完成,比如验证规则(Validation Rule)、工作流规则(Workflow Rule)等。如果可以,则优先使用它们。

Trigger 结构与触发事件

Trigger 的标准结构如下:

trigger Trigger名字 on 对象名字 (触发事件) {
// Do something
}

Trigger 类必须以关键字 “trigger” 开始,然后是此 Trigger 的名字。接下来是 “on” 关键字,然后是 Trigger 对应的对象的名字。对象名字后面的括号中写入触发 Trigger 的事件。

Trigger 的触发事件分为以下几种:

  • before insert:插入数据之前
  • before update:更新数据之前
  • before delete:删除数据之前
  • after insert:插入数据之后
  • after update:更新数据之后
  • after delete:删除数据之后
  • after undelete:恢复数据之后

比如:

trigger HelloWorldTrigger on Account (before insert, before update) {
System.debug('Hello World!');
}

这个 Trigger 在每一个 Account 对象插入或更新之前执行。

如果执行了如下代码:

Account a = new Account(Name='test');
insert a; a.Name = 'test2';
update a;

在这两个 DML 语句生效前,系统的日志中会添加 “Hello World!” 的记录。

Trigger 的预设变量

Trigger 类可以使用一些系统预设的变量,来辅助实现一些公共的操作。

Trigger.New 和 Trigger.Old

Trigger.New 和 Trigger.Old 是两个预定义变量,可以用于每一个 Trigger 类中。前者代表了即将被插入、更新的数据,后者代表了更新之前、删除之前的数据。它们可能包含一条数据,也可能包含一组数据,取决于触发 Trigger 时的状态。

要注意的是,Trigger.New 不存在于 delete 操作中,因为删除之后就没有数据了。而 Trigger.Old 不存在于 insert 操作中,因为插入数据之前是没有数据的。

在下面的代码中,我们可以为每一条即将被插入数据库的 Account 数据定义 Description 字段的值。

trigger HelloWorldTrigger on Account (before insert) {
for(Account acc : Trigger.New) {
acc.Description = 'New account desc';
}
}

通过这个 Trigger,当每一条 Account 数据被插入数据库之前,都会被定义 Description 字段的值。

布尔值变量

除了 Trigger.New 和 Trigger.Old,系统还提供了一系列的布尔值变量,用于标志 Trigger 或数据的状态。

最常用的有:

  • isInsert:是否是 insert 操作
  • isUpdate:是否是 update 操作
  • isDelete:是否是 delete 操作
  • isBefore:是否是操作之前
  • isAfter:是否是操作之后

在下面的代码中,我们可以定义对于不同的操作和不同的时机,写入不同的日志记录。

trigger HelloWorldTrigger on Account (before insert, after insert, before delete) {
if(Trigger.isInsert) {
if(Trigger.isBefore) {
System.debug('This is before insert');
} else if(Trigger.isAfter) {
System.debug('This is after insert');
}
} else if(Trigger.isDelete) {
System.debug('This is delete');
}
}

Trigger 中的错误处理

在 Trigger 中,我们可以为进行操作的数据进行验证,类似于验证规则。如果遇到不符合条件的数据,可以通过 addError() 函数来将错误显示给用户,并记录日志。

在如下代码中,当一个“业务机会”对象被插入或更新之前,系统会检查“金额”字段的值是否不小于1000。如果“金额”的数值小于1000,该“业务机会”记录将不能被插入或更新。

错误信息的显示适用于前端和后端:

  • 如果该记录是从用户页面修改的,则用户会看到错误信息
  • 如果该记录是从 Apex 程序中被插入或修改,则错误信息会被记录在日志中
trigger OppyMaxAmountTrigger on Opportunity (before insert, before update) {
for(Opportunity opp : Trigger.New) {
if(opp.amount < 1000) {
opp.addError('Amount should not be less than 1000!');
}
}
}

最佳实践:批量处理数据

由于 Trigger 类是在数据被操作的时候自动执行,而 Salesforce 是运行在云端的平台,所以对于 Trigger 类的一个最佳实践是:尽量批量处理数据,而非对每条数据在 Trigger 中单独处理。

比如在普通的 Apex 类中,有一段代码要更新一组 Contact 数据:

update contactList;

而系统中需要一个 Trigger 类在每个 Contact 对象更新之前设定其 FirstName 的值。

如果在 Trigger 中每次只处理一条数据,比如:

trigger ContactRenameTrigger on Contact (before update) {
Contact c = Trigger.New[0];
c.FirstName = 'default first name';
}

那么在一组 Contact 数据要更新的情况下,该 Trigger 会被执行很多次,每条数据一次。

如果将 Trigger 改为处理所有数据,比如:

trigger ContactRenameTrigger on Contact (before update) {
for(Contact c : Trigger.New) {
c.FirstName = 'default first name';
}
}

那么 Trigger 只需要执行一次,就可以将要处理的一组 Contact 数据中每条数据都进行更新,提高了效率。

在 Trigger 中也可以执行 SOQL 查询和 DML 操作。这时也要尽量先准备好一组数据,然后执行一次 DML 操作,而非对每一条记录单独执行一次。

比如,在更新每个 Account 数据之后,都要插入一条 Opportunity 数据,那么可以在 Trigger 中先用 SOQL 查询提取出所有的 Account 数据,然后对于每一个 Account 数据新建一个 Opportunity 数据,再一次性将所有的 Opportunity 数据用 DML 语句插入数据库中。

trigger AddOpportunityTrigger on Account (after update) {
List<Opportunity> oppList = new List<Opportunity>(); List<Account> accList = [SELECT Id, Name FROM Account WHERE Id IN :Trigger.New]; for(Account a : accList) {
oppList.add(new Opportunity(Name=a.Name+' opp',
StageName='Prospecting',
CloseDate=System.today().addMonths(1),
AccountId=a.Id)
);
} if(oppList.size() > 0) {
insert oppList;
}
}

在上面的代码中,只执行了一次 SOQL 和 DML 语句。

如果在 for 循环中用 SOQL 单独查询出每一条 Account 的数据,然后新建一个 Opportunity 数据,并用 DML 插入这一条数据,那么执行效率会大大降低。

Apex 的 Trigger 类简介的更多相关文章

  1. ImageView类简介

    4.8  图片控件 本节将要介绍的是图片控件ImageView,首先对ImageView类进行简单介绍,然后通过一个案例来说明ImageView的用法. 4.8.1  ImageView类简介 Ima ...

  2. Spring Security——核心类简介——获得登录用户的相关信息

    核心类简介 目录 1.1     Authentication 1.2     SecurityContextHolder 1.3     AuthenticationManager和Authenti ...

  3. DriverManager 驱动管理器类简介 JDBC简介(三)

    驱动程序管理器是负责管理驱动程序的,驱动注册以后,会保存在DriverManager中的已注册列表中 后续的处理就可以对这个列表进行操作 简言之,驱动管理器,就是字面含义,主要负责就是管理 驱动 概述 ...

  4. Java基础-日期格式化DateFormat类简介

    Java基础-日期格式化DateFormat类简介 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.DateFormat类概述 DateFormat 是日期/时间格式化子类的抽象 ...

  5. Java基础-StringBuffer类与StringBuilder类简介

    Java基础-StringBuffer类与StringBuilder类简介 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.StringBuffer类 在学习过String类之后 ...

  6. 34、Collections工具类简介

    Collections工具类简介 就像数组中的Arrays工具类一样,在集合里面也有跟Arrays类似的工具类Collections package com.sutaoyu.Collections; ...

  7. JAVA nio 2 和 Path 类简介

    想要初步了解 NIO.2 API,也就是通常所说的“JSR203: More New I/O APIs for the Java Platform”,最好的切入点就是新的抽象类 java.nio.fi ...

  8. QT中QWidget类简介

    一.详细描述 QWidget类是所有用户界面对象的基类.通俗的来讲,Qt基本上所有的UI类都是由QWidget继承出来的,而QWidget继承于QObject,  大家可以查阅Qt source 即可 ...

  9. Java并发包中CopyOnWrite容器相关类简介

    简介: 本文是主要介绍,并发容器CopyOnWriteArrayList和CopyOnWriteArraySet(不含重复元素的并发容器)的基本原理和使用示例. 欢迎探讨,如有错误敬请指正 如需转载, ...

随机推荐

  1. Java 中 & | ^ 运算符的简单使用

    背景 今天碰到了代码中的按位与运算,复习一下,先列一个各个进制数据表. 顺便复习一下十进制转二进制的计算方式: 接下来解释下这三个运算符: & 按位与,都转为二进制的情况下,同为1则为1,否则 ...

  2. react写一个todo

    概述 最近学习redux,打算先复习一下react,所以用react写了一个todo.记录下来,供以后开发时参考,相信对其他人也有用. 代码 代码请见我的github 组织架构如下图:

  3. Swift5 语言指南(十四) 下标

    类,结构和枚举可以定义下标,下标是用于访问集合,列表或序列的成员元素的快捷方式.您可以使用下标按索引设置和检索值,而无需单独的设置和检索方法.例如,您可以访问在元素Array实例作为someArray ...

  4. C#6.0语言规范(四) 类型

    C#语言的类型分为两大类:值类型和引用类型.值类型和引用类型都可以是泛型类型,它们采用一个或多个类型参数.类型参数可以指定值类型和引用类型. type : value_type | reference ...

  5. docker系统学习之docker界面管理

    docker可视化界面 dockerUI已废弃,转投Portainer项目 Portainer,轻量级管理界面,基本满足中小单位需求 官方Github https://github.com/porta ...

  6. LeetCode:144_Binary Tree Preorder Traversal | 二叉树的前序遍历 | Medium

    题目:Binary Tree Preorder Traversal 二叉树的前序遍历,同样使用栈来解,代码如下: struct TreeNode { int val; TreeNode* left; ...

  7. HoloLens开发手记 - 使用Visual Studio Using Visual Studio

    不论你是否使用DirectX或Unity来开发全息应用,你都会使用Visual Studio 2015来进行调试和部署应用.在本部分,你将会学习以下内容: 如何通过Visual Studio将你的应用 ...

  8. 构建NTP时间服务器

    NTP服务器是用于局域网服务器时间同步使用的,可以保证局域网所有的服务器与时间服务器的时间保持一致,某些应用对时间实时性要求高的必须统一时间. 互联网的时间服务器也有很多,例如ntpdate ntp. ...

  9. 使用Masonry对UIScrollView自动布局

    之前使用Masonry对UIScrollView进行过约束,当时是遇到了问题的,怎么约束都不对,因为赶进度直接改用frame了也没有对问题深究.就这样过了很久.........,直到前一段换工作的时候 ...

  10. Oracle的数据并发与一致性详解(下)

    上篇介绍了数据并发与一致性的相关概念.以及oracle的事务隔离级别等内容,本篇继续介绍锁机制.自动锁.手动锁.用户自定义锁的相关内容. 请尊重作者劳动成果,转载请标明原文链接: https://ww ...