可以使用触发器调用 Apex。Apex 触发器使您能够执行 在更改 Salesforce 记录之前或之后执行自定义操作,例如插入、更新或 删除。触发器是在以下类型的操作之前或之后执行的 Apex 代码:
- 插入
- 更新
- 删除
- 合并
- 更新插入
- 取消删除
例如,您可以在将对象的记录插入到 数据库,在删除记录之后,甚至在从回收中恢复记录之后 站。
您可以为支持触发器的顶级标准对象定义触发器,例如 联系人或客户、一些标准子对象(如 CaseComment)和自定义对象。 要定义触发器,请从触发其对象的对象管理设置中 想要访问,请转到触发器。有两种类型的触发器:
- 在触发器用于更新或验证记录值之前 保存到数据库。
- 使用触发器访问系统设置的字段值后 (例如记录或字段),并影响其他 记录,例如登录到审计表或异步触发 具有队列的事件。触发后触发器的记录是 只读。IdLastModifiedDate
触发器还可以修改与最初触发的记录类型相同的其他记录 触发器。例如,如果在更新联系人后触发触发器, 触发器还可以修改联系人 、 和 。因为触发器可能会导致其他记录更改,并且因为这些 反过来,更改可以触发更多触发器,Apex 运行时引擎会考虑所有这些 操作单个工作单元,并对可以 执行以防止无限递归。请参阅执行调控器和限制。
此外,如果在触发器之前更新或删除记录,或者删除 触发后,您将收到运行时错误。这包括直接和间接 操作。例如,如果更新帐户,则更新之前 触发帐户插入联系人,以及之后 插入客户联系人查询的触发器和 使用 DML 语句或数据库对其进行更新 方法,那么您正在间接更新其触发器中的帐户, 您将收到运行时错误。
实施注意事项
在创建触发器之前,请考虑以下事项:
- upsert触发器在触发器之前和之后或触发器之前和之后触发。insertupdate
- merge触发器在丢失记录之前和之后都会触发,并且在之前都会触发 以及触发获胜记录之后。 请参阅触发器和合并 语句。deleteupdate
- 在取消删除记录后执行的触发器仅适用于特定对象。 查看触发器和恢复 记录。
- 在触发器结束之前,不会记录字段历史记录。如果在 触发器时,您看不到当前交易的任何历史记录。
- 字段历史记录跟踪遵循 当前用户。如果当前用户没有直接编辑对象的权限,或者 字段,但用户激活了一个触发器,该触发器使用历史记录更改对象或字段 启用跟踪后,不会记录任何更改历史记录。
- 标注必须从触发器异步进行,以便触发器进程不会 在等待外部服务的响应时被阻止。异步标注是 在后台进程中制作,并在外部服务收到响应 返回它。要进行异步标注,请使用异步 Apex,例如 future 方法。有关更多信息,请参阅使用 Apex 调用标注。
- 在 API 版本 20.0 及更早版本中,如果批量 API 请求导致触发器触发,则每个 触发器要处理的 200 条记录的块被拆分为 100 条记录的块。在 Salesforce API 版本 21.0 及更高版本,不会发生进一步的 API 区块拆分。如果批量 API 请求导致触发器多次触发 200 条记录的块,调控器 在对同一 HTTP 请求的这些触发器调用之间重置限制。
- 批量触发器
- 触发器语法
- 触发上下文变量
- 上下文变量注意事项
- 常见的批量触发习惯用语
- 定义触发器
- 触发器和合并语句
- 触发器和恢复的记录
- 触发器和执行顺序
- 不调用触发器的操作
某些操作不调用触发器。 - 触发器中的实体和字段注意事项 创建触发器
时,请考虑某些实体、字段和操作的行为。 - Chatter 对象的触发器 您可以为 FeedItem 和 FeedComment 对象
编写触发器。 - 知识文章
的触发器注意事项 可以为 KnowledgeArticleVersion 对象编写触发器。了解何时可以使用触发器,以及哪些操作不会触发触发器,例如存档文章。 - 触发异常
- 触发器和批量请求最佳实践
批量触发器
默认情况下,所有触发器都是批量触发器,并且可以同时处理多条记录 时间。您应始终计划一次处理多条记录。
注意
定义为重复的 Event 对象不会针对 、 或 触发器进行批量处理。insertdeleteupdate批量触发器可以处理单个记录更新和批量操作,例如:
- 数据导入
- Lightning 平台批量 API 调用
- 批量操作,例如记录所有者更改和删除
- 调用批量 DML 语句的递归 Apex 方法和触发器
触发器语法
定义 触发器,请使用以下命令 语法:
trigger TriggerName on ObjectName (trigger_events) {
code_block
}
其中可以是一个或多个逗号分隔的列表 以下事件:
- before insert
- before update
- before delete
- after insert
- after update
- after delete
- after undelete
注意
- 由 、 或 重复事件调用的触发器,或者 调用触发器时,重复任务会导致运行时错误 从 Lightning 平台 API 批量。insertdeleteupdate
- 假设您使用插入后或更新后触发器来更改 潜在顾客、联系人或商机的所有权。如果您使用 API 执行以下操作 更改记录所有权,或者如果 Lightning Experience 用户更改了 记录的所有者,则不会发送电子邮件通知。发送电子邮件 通知记录的新所有者,将属性设置为 DMLOptions 更改为 .triggerUserEmailtrue
例如,以下代码定义了 Account 上 和 事件的触发器 对象:before insertbefore update
trigger myAccountTrigger on Account (before insert, before update) {
// Your code here
}
触发器的代码块不能包含关键字。触发器只能 包含适用于内部类的关键字。此外,你做 无需手动提交触发器所做的任何数据库更改。static如果 Apex 触发器成功完成,则会自动更改任何数据库 承诺。如果您的 Apex 触发器未成功完成,则对 数据库已回滚。
触发上下文变量
所有触发器都定义了允许开发人员使用的隐式变量 以访问运行时上下文。这些变量包含在类中。System.Trigger
变量 | 用法 |
---|---|
isExecuting | 如果 Apex 代码的当前上下文是触发器,则返回 true, 不是 Visualforce 页面、Web 服务或 API 调用。executeanonymous() |
isInsert | 如果此触发器,则返回 由于 Salesforce 用户的插入操作而触发 接口、Apex 或 API。true |
isUpdate | 如果此触发器,则返回 由于 Salesforce 用户的更新操作而触发 接口、Apex 或 API。true |
isDelete | 如果此触发器,则返回 由于删除操作而触发,从 Salesforce 用户界面, Apex 或 API。true |
isBefore | 如果此触发器,则返回 在保存任何记录之前就被解雇了。true |
isAfter | 如果此触发器,则返回 在保存所有记录后被解雇。true |
isUndelete | 如果此触发器,则返回 在从回收站中恢复记录后被触发。这 在 Salesforce 用户执行撤消删除操作后,可能会发生恢复 接口、Apex 或 API。true |
new | 返回 sObject 记录的新版本的列表。这 sObject 列表仅在 、 、 中可用 和触发器,以及 只能在触发器中修改记录。insertupdateundeletebefore |
newMap | 指向 sObject 记录新版本的 ID 的映射。这张地图 仅在 、 、 和 触发器中可用。before updateafter insertafter updateafter undelete |
old | 返回旧版本的 sObject 记录的列表。这 sObject 列表仅在 和 触发器中可用。updatedelete |
oldMap | 旧版本的 sObject 记录的 ID 映射。这张地图 仅在 和 触发器中可用。updatedelete |
operationType | 返回 System.TriggerOperation 类型的枚举,对应于 当前操作。System.TriggerOperation 枚举的可能值 分别是:、、,, , ,和。如果您改变您的 基于不同触发器类型的编程逻辑,考虑使用 带有 唯一触发器执行枚举的不同排列 国家。BEFORE_INSERTBEFORE_UPDATEBEFORE_DELETEAFTER_INSERTAFTER_UPDATEAFTER_DELETEAFTER_UNDELETEswitch |
size | 触发器调用中的记录总数,包括旧的和 新增功能。 |
注意
触发触发器的记录可以包含无效字段 value,例如除以零的公式。在本例中,字段值在以下变量中设置为:null
- new
- newMap
- old
- oldMap
例如,在这个简单的触发器中,是一个可以迭代的 sObject 列表 循环过来。它也可以用作绑定 变量。Trigger.newforIN
Trigger simpleTrigger on Account (after insert) {
for (Account a : Trigger.new) {
// Iterate over each sObject
}
// This single query finds every contact that is associated with any of the
// triggering accounts. Note that although Trigger.new is a collection of
// records, when used as a bind variable in a SOQL query, Apex automatically
// transforms the list of records into a list of corresponding Ids.
Contact[] cons = [SELECT LastName FROM Contact
WHERE AccountId IN :Trigger.new];
}
此触发器使用布尔上下文变量(如 和)来定义仅执行的代码 对于特定的触发条件:Trigger.isBeforeTrigger.isDelete
trigger myAccountTrigger on Account(before delete, before insert, before update,
after delete, after insert, after update) {
if (Trigger.isBefore) {
if (Trigger.isDelete) {
// In a before delete trigger, the trigger accesses the records that will be
// deleted with the Trigger.old list.
for (Account a : Trigger.old) {
if (a.name != 'okToDelete') {
a.addError('You can\'t delete this record!');
}
}
} else {
// In before insert or before update triggers, the trigger accesses the new records
// with the Trigger.new list.
for (Account a : Trigger.new) {
if (a.name == 'bad') {
a.name.addError('Bad name');
}
}
if (Trigger.isInsert) {
for (Account a : Trigger.new) {
System.assertEquals('xxx', a.accountNumber);
System.assertEquals('industry', a.industry);
System.assertEquals(100, a.numberofemployees);
System.assertEquals(100.0, a.annualrevenue);
a.accountNumber = 'yyy';
}
// If the trigger is not a before trigger, it must be an after trigger.
} else {
if (Trigger.isInsert) {
List<Contact> contacts = new List<Contact>();
for (Account a : Trigger.new) {
if(a.Name == 'makeContact') {
contacts.add(new Contact (LastName = a.Name,
AccountId = a.Id));
}
}
insert contacts;
}
}
}}}
上下文变量注意事项
请注意触发器上下文变量的以下注意事项:
- trigger.new并且不能用于 Apex DML 操作。trigger.old
- 您可以使用对象来更改其自己的字段值,但只能在触发器之前使用。在所有触发器之后,不会保存,因此运行时异常是 扔。trigger.newtrigger.new
- trigger.old始终是只读的。
- 您无法删除 .trigger.new
下表列出了有关不同触发器事件中某些操作的注意事项:
常见的批量触发习惯用语
尽管批量触发器允许开发人员处理更多记录 在不超出执行调控器限制的情况下,它们可能会更加困难 供开发人员理解和编码,因为它们涉及处理 一次批处理多条记录。以下各节提供 写作时应经常使用的成语示例 散装。
在批量触发器中使用映射和集
设置 和 MAP 数据结构对于成功进行批量编码至关重要 触发器。集可用于隔离不同的记录,而映射 可用于保存按记录 ID 组织的查询结果。
为 例如,此批量触发器首先来自示例引用应用程序 添加与 OpportunityLineItem 关联的每个价目表条目 记录到 一个集合,确保该集合仅包含不同的元素。然后 查询 PricebookEntries 以获取其关联的产品颜色,以及 将结果放置在地图中。创建地图后,触发器 循环访问 中的 OpportunityLineItems,并使用映射来分配 适当的颜色。Trigger.newTrigger.new
// When a new line item is added to an opportunity, this trigger copies the value of the
// associated product's color to the new record.
trigger oppLineTrigger on OpportunityLineItem (before insert) {
// For every OpportunityLineItem record, add its associated pricebook entry
// to a set so there are no duplicates.
Set<Id> pbeIds = new Set<Id>();
for (OpportunityLineItem oli : Trigger.new)
pbeIds.add(oli.pricebookentryid);
// Query the PricebookEntries for their associated product color and place the results
// in a map.
Map<Id, PricebookEntry> entries = new Map<Id, PricebookEntry>(
[select product2.color__c from pricebookentry
where id in :pbeIds]);
// Now use the map to set the appropriate color on every OpportunityLineItem processed
// by the trigger.
for (OpportunityLineItem oli : Trigger.new)
oli.color__c = entries.get(oli.pricebookEntryId).product2.color__c;
}
在批量触发器中将记录与查询结果相关联
使用 和 ID to-sObject 映射以将记录与查询结果相关联。例如,此触发器 从示例引用应用程序用于创建一组唯一 ID ()。然后,该集用作查询的一部分,以创建报价列表 与触发器正在处理的商机相关联。 对于查询返回的每个报价,相关的商机是 检索自并防止被删除:Trigger.newMapTrigger.oldMapTrigger.oldMapTrigger.oldMap.keySet()Trigger.oldMap
trigger oppTrigger on Opportunity (before delete) {
for (Quote__c q : [SELECT opportunity__c FROM quote__c
WHERE opportunity__c IN :Trigger.oldMap.keySet()]) {
Trigger.oldMap.get(q.opportunity__c).addError('Cannot delete
opportunity with a quote');
}
}
使用触发器插入或更新具有唯一值的记录 领域
当 或 事件导致 在另一条新记录中复制唯一字段值的记录 在该批处理中,重复记录的错误消息包括 第一条记录的 ID。但是,错误可能是 请求完成时,消息可能不正确。insertupsert
当存在触发器时,批量操作中的重试逻辑 导致发生回滚/重试周期。该重试周期会分配新的 新记录的键。例如,如果插入了两条记录 具有唯一字段的相同值,并且您还为触发器定义了一个事件, 第二条重复记录失败,报告第一条记录的 ID。 但是,一旦系统回滚更改并重新插入 第一条记录本身,该记录将收到一个新 ID。这意味着 第二条记录报告的错误消息不再有效。insert
定义触发器
触发器代码作为元数据存储在与其关联的对象下。要定义一个 Salesforce 中的触发器:
- 从要触发其对象的对象的对象管理设置中 访问,转到触发器。提示对于 Attachment、ContentDocument 和 Note 标准对象,无法创建 Salesforce 用户界面中的触发器。对于这些对象,创建一个触发器 使用开发工具,例如开发人员控制台或 Salesforce Visual Studio Code 的扩展。或者,您也可以使用元数据 应用程序接口。
- 在“触发器”列表中,单击“新建”。
- 要指定 Apex 的版本和用于此触发器的 API,请单击“版本” 设置。如果您的组织已从 AppExchange,您还可以指定要使用的每个托管软件包的版本 使用此触发器。将触发器与最新版本的 Apex 关联,然后 API 和每个托管包,使用所有版本的默认值。你 如果要访问组件,可以指定旧版本的托管包 或与最新包版本不同的功能。
- 单击 Apex Trigger,然后选中 Is Active 复选框,如果您 想要编译并启用触发器。如果仅 想要将代码存储在组织的元数据中。此复选框由 违约。
- 在正文文本框中,输入触发器的顶点。单个 触发器的长度最多为 100 万个字符。定义 触发器,请使用以下命令 语法:
trigger TriggerName on ObjectName (trigger_events) { code_block }
其中可以是一个或多个逗号分隔的列表 以下事件:trigger_events- before insert
- before update
- before delete
- after insert
- after update
- after delete
- after undelete
- 由 、 或 重复事件调用的触发器,或者 调用触发器时,重复任务会导致运行时错误 从 Lightning 平台 API 批量。insertdeleteupdate
- 假设您使用插入后或更新后触发器来更改 潜在顾客、联系人或商机的所有权。如果您使用 API 执行以下操作 更改记录所有权,或者如果 Lightning Experience 用户更改了 记录的所有者,则不会发送电子邮件通知。发送电子邮件 通知记录的新所有者,将属性设置为 DMLOptions 更改为 .triggerUserEmailtrue
- 点击保存。
注意
触发器使用设置为 只要依赖元数据自上次编译触发器以来未更改。如果有的话 对触发器中使用的对象名称或字段进行更改,包括 表面更改(例如对对象或字段描述的编辑),该标志将设置为直到 Apex 编译器重新处理代码。重新编译发生在以下情况下 触发器将在下次执行时执行,或者当用户在元数据中重新保存触发器时执行。isValidtrueisValidfalse
如果 查找字段引用已删除的记录,Salesforce 将清除 默认的查找字段。或者,您可以选择阻止记录 如果它们处于查找关系中,则删除。
Apex 触发器编辑器
Apex 和 Visualforce 编辑器具有以下功能:语法高亮显示编辑器会自动对关键字和所有关键字应用语法高亮显示 函数和运算符。搜索 ()通过搜索,可以在当前页面、类或 触发。若要使用搜索,请在“搜索”文本框中输入字符串,然后单击“查找下一个”。
- 要将找到的搜索字符串替换为另一个字符串,请输入新的 字符串,然后单击“替换”以仅替换该实例,或单击“全部替换”以替换该实例,然后单击“全部替换”以替换该实例,然后单击“替换” 页面中出现的搜索字符串的所有其他实例, 类或触发器。
- 若要使搜索操作区分大小写,请选择“匹配大小写”选项。
- 若要使用正则表达式作为搜索字符串,请选择“正则表达式”选项。常规 表达式遵循 JavaScript 的正则表达式规则。搜索 使用正则表达式可以找到换行超过 一行。如果将 replace 操作与 找到的字符串一起使用 一个正则表达式,替换操作也可以绑定 正则表达式组变量(、 等) 找到搜索字符串。例如,要将标签替换为标签,并保留所有 属性对原来完好无损,搜索并替换它 跟。$1$2<h1><h2><h1><h1(\s+)(.*)><h2$1$2>
转到行
此按钮允许您突出显示指定的行号。如果该行是 当前不可见,编辑器将滚动到该行。
撤消 和重做
使用撤消可撤消编辑操作,使用重做可重新创建编辑操作 那被撤消了。
字体大小
从下拉列表中选择字体大小以控制 编辑器中显示的字符。
行和列位置
光标的行和列位置显示在状态栏中 编辑器的底部。这可以与转到行 (Go To Line icon) 一起使用,以快速浏览编辑器。
行数和字符数
行数和字符总数显示在状态栏中 编辑器的底部。
触发器和合并语句
合并事件不会触发自己的触发事件。相反,他们 触发删除和更新事件,如下所示:删除丢失的记录单个合并操作会为所有记录触发单个删除事件 在合并中删除的。确定删除了哪些记录 合并操作的结果是使用 中的字段。在丢失合并后删除记录时 操作,则其字段设置为中奖记录的 ID。该字段仅设置 在触发事件中。 如果您的应用程序需要对已删除的记录进行特殊处理 由于合并而发生,则需要使用 Trigger 事件。MasterRecordIdTrigger.oldMasterRecordIdMasterRecordIdafter deleteafter delete更新中奖记录单个合并操作会为获胜的单个更新事件触发 仅记录。由于以下原因而重新设置父级的任何子记录 合并操作不会触发触发器。
例如,如果合并了两个联系人,则只有删除和更新 接触触发火灾。没有触发与联系人相关的记录, 如客户或商机,火。以下是合并发生时事件的顺序:
- 触发器 火灾。before delete
- 系统会因合并而删除必要的记录,分配 新的父记录到子记录,并在已删除的 记录。MasterRecordId
- 触发器 火灾。after delete
- 系统执行主记录所需的特定更新。 正常的更新触发器适用。
触发器和恢复的记录
触发事件仅适用于 恢复的记录 – 即已删除然后从回收站中恢复的记录 通过 DML 语句。这些也称为 未删除的记录。after undeleteundelete
触发器事件仅在顶级上运行 对象。例如,如果您删除一个帐户,则 Opportunity 也可能被删除。当您恢复时 回收站中的帐户,商机也会被恢复。如果存在与帐户和 Opportunity,只有 Account 触发器 事件执行。after undeleteafter undeleteafter undelete触发器 事件仅针对以下对象触发:
- 客户
- 资产
- 运动
- 个案
- 联系
- 内容文档
- 合同
- 自定义对象
- 事件
- 潜客
- 机会
- 产品
- 解决方案
- 任务
触发器和执行顺序
当您使用 、 或语句保存记录时,Salesforce 会在某个 次序。insertupdateupsert
在 Salesforce 在服务器上执行这些事件之前,浏览器会运行 JavaScript 验证记录是否包含任何依赖的选择列表字段。验证限制 每个从属选择列表字段设置为其可用值。不会对 客户端。
注意
有关执行顺序的图示表示形式,请参阅执行顺序 Salesforce Architects 网站上的概述。这 diagram 特定于其上指示的 API 版本,并且可能与 信息在这里。此 Apex 开发人员指南页面包含最新的 有关此 API 版本的执行顺序的信息。访问其他 API 版本,请使用 Apex 开发人员的版本选择器 指南。
在服务器上,Salesforce 按此顺序执行事件。
- 从数据库加载原始记录或初始化语句的记录。upsert
- 从请求中加载新的记录字段值并覆盖旧的记录字段值 值。Salesforce 根据类型执行不同的验证检查 的请求。
- 对于来自标准 UI 编辑页面的请求,Salesforce 会运行这些系统 对记录进行验证检查:
- 符合特定于布局的规则
- 布局级别和字段定义的必需值 水平
- 有效字段格式
- 最大视场长度
- 对于来自创建多行项目(例如报价单项目)的请求,以及 商机行项时,Salesforce 会运行自定义验证规则。
- 对于来自其他来源(如 Apex 应用程序或 SOAP)的请求 API 调用时,Salesforce 仅验证外键并受限制 选择列表。在执行触发器之前,Salesforce 会验证任何 自定义外键不引用对象本身。
- 对于来自标准 UI 编辑页面的请求,Salesforce 会运行这些系统 对记录进行验证检查:
- 执行记录触发的流,这些流配置为在记录之前运行 保存。
- 执行所有触发器。before
- 再次运行大多数系统验证步骤,例如验证所有必需的步骤 字段具有非值,并运行 任何自定义验证规则。Salesforce 唯一没有的系统验证 第二次运行(当请求来自标准 UI 编辑页面时)是 强制执行特定于布局的规则。null
- 执行重复的规则。如果重复规则将记录标识为 复制并使用阻止操作,则不会保存记录,也不会进一步保存 步骤,例如触发器和 工作流规则,被采用。after
- 将记录保存到数据库,但尚未提交。
- 执行所有触发器。after
- 执行分配规则。
- 执行自动响应规则。
- 执行工作流规则。如果有工作流字段更新:注意这个序列 仅适用于工作流规则。
- 再次更新记录。
- 再次运行系统验证。自定义验证规则、流程、重复 规则、流程和升级规则不会再次运行。
- 执行触发器 和触发器, 无论记录操作如何(插入或更新),再进行一次 (而且只有一次)before updateafter update
- 执行升级规则。
- 执行这些 Salesforce Flow 自动化,但不是按保证的顺序执行。
- 过程
- 进程启动的流
- 工作流规则启动的流(流触发器 工作流操作试点)
- 执行记录触发的流,这些流配置为在记录 保存
- 执行授权规则。
- 如果记录包含汇总摘要字段或属于跨对象 工作流,执行计算并更新 父记录。父记录经过保存过程。
- 如果父记录已更新,并且祖父级记录包含汇总 摘要字段或是跨对象工作流的一部分,执行计算和 更新祖父母记录中的汇总摘要字段。祖父母记录 完成保存过程。
- 执行基于条件的共享评估。
- 将所有 DML 操作提交到数据库。
- 将更改提交到数据库后,执行提交后逻辑是 执行。提交后逻辑的示例(排名不分先后)包括:
- 发送电子邮件
- 排队的异步 Apex 作业,包括可排队的作业和未来的 方法
- 记录触发流中的异步路径
注意
在递归保存期间,Salesforce 会跳过第 9 步(分配规则)到 17 (祖父母记录中的汇总摘要字段)。
其他注意事项
使用触发器时,请注意以下注意事项。
- 如果工作流规则字段更新由记录更新触发,则不会保存新更新的 字段。相反,在初始记录更新之前保留对象 䍬。例如,现有记录具有一个初始值的数字字段 的 1.用户将此字段更新为 10,并触发工作流规则字段更新 并将其递增为 11。在工作流字段更新后触发的触发器中, 从中获取的对象是 原始值为 1,而不是 10。请参阅更新前后的 Trigger.old 值 触发器。Trigger.oldTrigger.oldupdateTrigger.old
- 如果在允许部分成功的情况下进行 DML 调用,则会在 第一次尝试,并在随后的尝试中再次发射。因为这些 触发器调用是同一事务的一部分,静态类变量 触发器访问的不会重置。请参阅批量 DML 异常处理。
- 如果在同一个事件的对象上定义了多个触发器,则顺序 不保证触发器的执行。例如,如果 Case 有两个触发器,一个新的触发器 插入案例记录。这两个触发器的触发顺序不是 保证。before insert
- 了解在 将联系人关联到多个帐户的组织,请参阅 AccountContactRelation。
- 了解执行顺序 使用触发器设置阶段和预测类别, 请参阅商机。before
- 在 API 版本 53.0 及更早版本中,保存后记录触发的流在 权利被执行。
不调用触发器的操作
某些操作不会调用触发器。触发器是为 Java 应用程序服务器启动或处理。因此,某些系统批量操作不会调用 触发器。一些例子包括:
- 级联删除操作。未启动的记录不会导致触发器评估。delete
- 由于合并而重新设置父级的子记录的级联更新 操作
- 大规模广告系列状态更改
- 分质转移
- 群发地址更新
- 批量批准请求转移
- 群发电子邮件操作
- 修改自定义字段数据类型
- 重命名或替换选择列表
- 管理价目表
- 在选中传输分部选项的情况下更改用户的默认分部
- 对以下对象的更改:
- 品牌模板
- MassEmailTemplate(马斯电子邮件模板)
- 文件夹
- 更新帐户触发器不会在企业帐户记录类型之前或之后触发 更改为个人帐户(或个人帐户记录类型更改为业务 帐户。
- 当计数器增加时,更新触发器不会触发。FeedItemLikeCount
注意
在个人帐户上插入、更新和删除会触发帐户触发器,而不是联系人 触发器。与以下内容关联的触发器 仅当潜在客户的验证和触发时,才会在潜在客户转换期间触发操作 在组织中启用转换:
before
- insert客户、联系人和 机会
- update客户和联系人数量
当帐户所有者因 关联商机的所有者正在更改。
在以下情况下,不会触发 and 触发器和验证规则:beforeafter
- 在商机上修改商机产品。
- 商机产品计划会更改商机产品,即使商机 产品改变机会。
但是,汇总摘要字段确实会更新,并且与 机会确实在运行。
触发器中不允许使用 和 PageReference 方法。getContentgetContentAsPDF
请注意 ContentVersion 对象的以下事项:
- 涉及 ContentVersion 对象的内容包操作,包括幻灯片和幻灯片 autorevision,不要调用触发器。注意当幻灯片内的内容包被修改时 包已修订。
- TagCsv 和 VersionData 字段的值为 仅当请求创建或更新 ContentVersion 记录时,触发器中才可用 源自 API。
- 不能将 ContentVersion 对象与 ContentVersion 对象一起使用或触发器。beforeafter delete
在以下情况下,不会触发 Attachment 对象上的触发器:
- 附件是通过案例源发布者创建的。
- 用户通过“电子邮件相关”列表发送电子邮件并添加附件文件。
当通过 Email-to-Case 或 UI 创建 Attachment 对象时,触发器将触发。
触发器中的实体和字段注意事项
创建触发器时,请考虑某些实体、字段和 操作。
QuestionDataCategorySelection 实体在插入后不可用 触发器
触发后触发的触发器 插入一条或多条记录 无权访问与 插入 s。例如, 以下查询不会在触发器中返回任何结果:
after insertQuestionQuestionDataCategorySelectionQuestionafter insert
QuestionDataCategorySelection[] dcList =
[select Id,DataCategoryName from QuestionDataCategorySelection where ParentId IN :questions];
在触发器之前不可更新的字段
某些字段值是在触发器触发后发生的系统保存操作期间设置的。作为 结果,这些字段无法在 OR 触发器中修改或准确检测。一些例子包括:
beforebefore insertbefore update
- Task.isClosed
- Opportunity.amount*
- Opportunity.ForecastCategory
- Opportunity.isWon
- Opportunity.isClosed
- Contract.activatedDate
- Contract.activatedById
- Case.isClosed
- Solution.isReviewed
- Id(所有记录)**
- createdDate(对于所有人 记录)**
- lastUpdated(所有记录)
- Event.WhoId(当共享活动 已启用)
- Task.WhoId(当共享活动 已启用)
* 当没有时,可以通过触发器进行修改。OpportunitylineitemsAmountbefore
** Id并且可以在触发器中检测到,但无法修改。createdDatebefore update
触发后无法更新的字段
以下字段不能由 或 触发器更新。after insertafter update
- Event.WhoId
- Task.WhoId
插入和更新触发器中事件日期时间字段的注意事项
我们建议使用以下日期和时间字段来创建或更新事件。
- 创建或更新定时事件时,请使用以避免日期和时间不一致的问题 值。ActivityDateTime
- 创建或更新全天活动时,请使用以避免日期和时间不一致的问题 值。ActivityDate
- 我们建议您使用,因为它适用于所有更新和为事件创建。DurationInMinutes
插入和更新触发器中不支持的操作
和触发器不支持以下操作。insertupdate
- 通过 or 对象操作活动关系(如果启用了共享活动)TaskRelationEventRelation
- 通过对象操作组事件的受邀者关系,无论是否共享 活动已启用Invitee
取消删除后触发器中不支持的实体
某些对象无法还原,因此不应具有触发器。
after undelete
- 协作组
- 协作组成员
- 饲料项目
- FeedComment (英语)
更新触发器的注意事项
字段历史记录跟踪遵循当前用户的权限。 如果当前用户没有直接编辑对象或字段的权限,但 用户激活一个触发器,该触发器通过历史跟踪更改对象或字段 启用后,不会记录任何更改历史记录。
Salesforce for Outlook 的 Salesforce 侧面板的注意事项
当使用 Salesforce 侧面板将电子邮件关联到记录时 Salesforce for Outlook,电子邮件关联在任务记录的 or 字段中表示。关联在 任务已创建,因此 和 字段不会立即创建 可用于插入和更新的任务触发器 事件,其值最初是 。 和字段在后续任务记录中对保存的任务记录进行设置 但是,操作,以便以后可以检索其值。WhoId WhatId Task.WhoId Task.WhatId before after null WhoId WhatId
Chatter 对象的触发器
可以为 FeedItem 和 FeedComment 对象编写触发器。
FeedItem、FeedAttachment 和 FeedComment 的触发注意事项
- 只能插入 、 、 、 和 类型的 FeedItems,因此可以调用 or 触发器。用户状态更新不会导致 FeedItem 触发触发器。TextPostQuestionPostLinkPostHasLinkContentPostHasContentbeforeafter insert
- 虽然 API 版本 18.0、19.0 和 20.0 支持 FeedPost 对象, 不要使用针对 21.0 之前的版本保存的任何插入或删除触发器。
- 对于 FeedItem,触发器中不提供以下字段:before insert
- 内容大小
- 内容类型
- FeedItem 对象上的触发器在其 附件和功能信息被保存,这意味着信息和信息可能不会被保存 在触发器中可用。ConnectApi.FeedItem.attachmentConnectApi.FeedElement.capabilities附件和功能信息可能无法从以下位置获得 方法: 和ConnectApi.ChatterFeeds.getFeedItemConnectApi.ChatterFeeds.getFeedElementConnectApi.ChatterFeeds.getFeedPollConnectApi.ChatterFeeds.getFeedElementPollConnectApi.ChatterFeeds.postFeedItemConnectApi.ChatterFeeds.postFeedElementConnectApi.ChatterFeeds.shareFeedItemConnectApi.ChatterFeeds.shareFeedElementConnectApi.ChatterFeeds.voteOnFeedPollConnectApi.ChatterFeeds.voteOnFeedElementPoll
- FeedAttachment 不是可触发的对象。您可以在 FeedItem 更新通过 SOQL 查询触发。为 例:
trigger FeedItemTrigger on FeedItem (after update) { List<FeedAttachment> attachments = [SELECT Id, Title, Type, FeedEntityId FROM FeedAttachment WHERE FeedEntityId IN :Trigger.new ]; for (FeedAttachment attachment : attachments) { System.debug(attachment.Type); } }
- 插入带有关联附件的源项时,FeedItem 为 首先插入,然后创建 FeedAttachment 记录。更新源时 项目,则首先插入 FeedAttachment 记录, 然后更新 FeedItem。由于这一系列操作,在 Salesforce Classic FeedAttachment 在 和 触发器中可用。当通过 Lightning Experience 完成附件时,它是 在 和 触发器中均可用;但在触发器中,使用 future 方法 访问 FeedAttachments。UpdateAfterInsertUpdateAfterInsertAfterInsert
- 以下源附件操作会导致触发 FeedItem 更新触发器。
- 将 FeedAttachment 添加到 FeedItem 中,并使 FeedItem 类型 改变。
- 从 FeedItem 中删除 FeedAttachment 并导致 FeedItem 类型 来改变。
- 插入或更新 FeedAttachment 时,不会触发 FeedItem 触发器 不会导致关联的 FeedItem 发生更改。
- 不能在更新前和更新后 FeedItem 触发器中插入、更新或删除 FeedAttachments。
- 对于插入前和插入后触发的 FeedComment, 与 FeedComment 关联的 ContentVersion 字段(通过 获取)不是 可用。FeedComment.RelatedRecordId
其他 Chatter 触发器注意事项
- Apex 代码在 Chatter 上下文中执行时会使用额外的安全性。要发布到 专用组,则运行代码的用户必须是该组的成员。如果 running user 不是成员,可以将 CreatedById 字段设置为 FeedItem 记录中组的成员。
- 更新 CollaborationGroupMember 时, CollaborationGroup 也会自动更新,以确保成员 计数是正确的。因此,当 CollaborationGroupMember 或触发器运行时,CollaborationGroup 触发器也会运行。updatedeleteupdate
知识文章的触发注意事项
可以为 KnowledgeArticleVersion 对象编写触发器。了解何时可以使用 触发器,以及哪些操作不会触发触发器,例如存档文章。通常,KnowledgeArticleVersion (KAV) 记录可以使用以下触发器:
- 创建 KAV 记录会调用 和 触发器。这包括创建一个 文章,以及从存档、已发布和主语言文章创建草稿 使用“恢复”、“编辑为草稿”和“提交以供翻译” 行动。before insertafter insert
- 编辑现有 KAV 记录会调用 和 触发器。before updateafter update
- 删除 KAV 记录会调用 和 触发器。before deleteafter delete
- 导入文章会调用 和 触发器。导入文章 translations 还调用 and 触发器。before insertafter insertbefore updateafter update
更改 KAV 记录的发布状态的操作(如“发布”和“存档”)执行 不触发 Apex 或流触发器。但是,有时从 UI 发布文章会导致 要保存的文章,在这些情况下,AND 触发器 叫。before updateafter update
知识操作和顶点触发器
在为 KnowledgeArticleVersion 上的操作编写 Apex 触发器时,请考虑以下事项:保存、保存和关闭保存文章时,将调用 和 触发器。当一个新的 文章首次保存,和触发器工作 相反。before updateafter updatebefore insertafter insert编辑、编辑为草稿
- 编辑草稿翻译时,可以使用 和 触发器。before updateafter update
- 这 编辑 由于草稿操作从已发布的文章创建草稿,因此 和触发器触发。before insertafter insert
- 在 Salesforce Classic 中,当草稿主语言文章出现以下情况时,不会触发任何触发器 编辑。
- 在 Salesforce Classic 中,在以下情况下调用 和 触发器 从“文章管理”选项卡编辑存档的文章。这将创建一个草稿 KAV记录。before insertafter insert
取消、删除
在以下情况下调用 和 触发器:before deleteafter delete
- 删除翻译草稿时。
- 在 Salesforce Classic 的“文章管理”或“知识”选项卡中,在 编辑已发布的文章,然后单击“取消”。这将删除新的 草案。
提交翻译此操作将创建草稿翻译,因此通常可以使用 和 触发器。在 Salesforce Classic 中,当您从“知识”选项卡创建新文章时,可以使用 和 触发器,保存 它,然后提交翻译。和触发点火 当主语言文章当前正在编辑时,但不是从列表视图或 查看文章时。before insertafter insertbefore updateafter updatebefore updateafter update分配只有在这样做时才会调用 和 触发器 首先导致记录保存。当文章在 单击“分配”按钮。before updateafter update
不触发触发器的操作
以下操作无法触发 Apex 触发器:
- 从回收站中取消删除文章。
- 预览和存档文章。
对闪电迁移的影响
从 Salesforce Classic 中的 Knowledge 迁移到 Lightning Knowledge 会影响 Apex 触发器。在 KnowledgeArticleVersion 对象上编写 Apex 触发器会创建依赖项 并防止删除 KAV 对象。迁移具有多个 文章类型,您必须删除任何引用 KAV 文章类型。在迁移过程中,如果 Apex 仍然触发,管理员会看到一条错误消息 参考文章类型 KAV 对象在迁移过程中删除。如果您取消 闪电知识迁移,而 Apex 触发器存在引用新 KAV 对象, 管理员会收到通知,您必须删除 Apex 法典。
示例知识触发器
例如,您可以定义一个触发器,该触发器在文章出现以下情况时输入摘要文本: 创建。
trigger KAVTrigger on KAV_Type__kav (before insert) {
for (KAV_Type__kav kav : Trigger.New) {
kav.Summary__c = 'Updated article summary before insert';
}
}
触发异常
触发器可用于通过对记录或字段调用方法来防止发生 DML 操作。当用于 和 触发器中的记录以及触发器中的记录时,自定义错误消息显示在 应用程序界面并记录。addError()Trigger.newinsertupdateTrigger.olddelete
注意
如果将错误添加到触发器中,则用户体验到的响应时间延迟较少。before可以使用以下方法标记正在处理的记录的子集:
addError()
- 如果触发器是由 Apex 中的 DML 语句生成的,则任何一个错误都会导致 整个操作回滚。但是,运行时引擎仍会处理 编译错误综合列表的操作。
- 如果触发器是由 Lightning 平台 API 中的批量 DML 调用生成的,则运行时 引擎将不良记录放在一边,并尝试对以下记录进行部分保存 未生成错误。请参阅批量 DML 异常处理。
如果触发器引发未经处理的异常,则所有记录都标记为错误,并且没有 进行进一步处理。
触发器和批量请求最佳实践
一个常见的开发陷阱是假设触发器调用永远不会包含更多 超过一条记录。Apex 触发器经过优化,可批量运行,根据定义, 要求开发人员编写支持批量操作的逻辑。这是一个有缺陷的编程模式的示例。它假定只有一条记录是 在触发器调用期间拉入。虽然这可能支持大多数用户界面事件, 它不支持通过 SOAP API 调用的批量操作或 视觉力。
trigger MileageTrigger on Mileage__c (before insert, before update) {
User c = [SELECT Id FROM User WHERE mileageid__c = Trigger.new[0].id];
}
这是有缺陷的编程模式的另一个示例。它假设少于 100 在触发器调用期间,记录在范围内。如果发出的查询超过 100 个, 触发器将超出 SOQL 查询 限制。
trigger MileageTrigger on Mileage__c (before insert, before update) {
for(mileage__c m : Trigger.new){
User c = [SELECT Id FROM user WHERE mileageid__c = m.Id];
}
}
有关调控器限制的更多信息,请参阅执行调控器和 限制。此示例演示了支持触发器批量性质的正确模式,而 尊重州长 限制:
Trigger MileageTrigger on Mileage__c (before insert, before update) {
Set<ID> ids = Trigger.newMap.keySet();
List<User> c = [SELECT Id FROM user WHERE mileageid__c in :ids];
}
此模式通过将集合传递给集合,然后使用 单个 SOQL 查询。此模式捕获请求中的所有传入记录,同时 限制 SOQL 查询的数量。Trigger.new
设计批量程序的最佳实践
以下是此设计模式的最佳实践:
- 通过添加 记录到集合中,并针对这些记录执行 DML 操作 收集。
- 通过预处理记录和生成 集合,可以放在与子句一起使用的单个 SOQL 语句中。IN