在Salesforce中,触发器为你提供了一种在数据库操作(例如插入、更新或删除)发生之前或之后自动执行自定义的Apex代码的方法。
Triggers(触发器):触发器是特定于对象的代码块,当与该对象关联的指定事件发生时执行。比如,当一个新的记录被创建或一个现有的记录被修改时。
触发器类型:基于它们执行的时机,有两种类型的触发器:before triggers(在数据库操作之前执行)和 after triggers(在数据库操作之后执行)。
事件:Salesforce为触发器提供了多种事件,如:before insert, before update, after insert, after update, before delete, 和 after delete.
触发器和对象:触发器可以与所有自定义对象以及大多数标准对象关联。但是,有些标准对象(如User或Event)不支持触发器。
示例:
trigger AccountTrigger on Account (before insert) {
for(Account a : Trigger.new) {
a.Description = 'Created by Salesforcegogogo';
}
}
在此示例中,每当创建一个新的Account记录时,该触发器会自动为其Description字段赋值为"Created by Salesforcegogogo"。
批处理:触发器是为批处理设计的,这意味着你的触发器代码应该能够处理多个记录,而不只是一个。这是为了优化性能和处理大量数据。
顺序:如果一个对象上有多个触发器,不能保证这些触发器的执行顺序。
Trigger与Flow:虽然工作流和触发器都可以用于自动化过程,但触发器提供了更多的灵活性,因为你可以编写自定义的Apex代码。另一方面,工作流是基于点击即用(point-and-click)的配置。
总之,当你需要在数据库操作之前或之后执行自定义逻辑时,触发器是一个非常有用的工具。在编写触发器时,始终要考虑代码的效率和可维护性。
5.2.2 Trigger上下文变量
在Salesforce Apex中,当触发器执行时,系统提供了一组特殊的变量,称为上下文变量。这些变量允许你在触发器代码中访问正在运行的操作的相关记录和操作的特定属性。
Trigger 上下文变量概览
Trigger.new:这是一个包含所有新版本的sObject记录的列表。当insert和update触发器执行时,你可以使用这个变量。对于insert触发器,这代表了即将被插入的所有新记录。对于update触发器,这代表了所有即将被更新的记录的新版本。
for(Account a : Trigger.new) {
// 处理每个即将插入或更新的账户记录
}
Trigger.old:这是一个包含所有旧版本的sObject记录的列表。当update和delete触发器执行时,你可以使用这个变量。这允许你在update或delete操作中访问记录之前的状态。
for(Account a : Trigger.old) {
// 处理每个即将被更新或删除的账户记录的旧版本
}
Trigger.newMap 和 Trigger.oldMap:这些是sObject的映射,键是记录的ID。newMap包含insert和update触发器的新版本的记录,而oldMap包含update和delete触发器的旧版本的记录。
Map<Id, Account> newAccounts = Trigger.newMap;
Map<Id, Account> oldAccounts = Trigger.oldMap;
Trigger.isInsert, Trigger.isUpdate, Trigger.isDelete:这些布尔变量可以告诉你触发器是因为哪种操作(插入、更新或删除)而执行的。
Trigger.isBefore 和 Trigger.isAfter:这些布尔变量允许你确定触发器是在操作之前还是之后执行的。
Trigger.size:这个变量告诉你触发器上下文中受影响的记录的数量。
利用上下文变量,你可以为正在进行的特定操作编写有条件的逻辑,例如仅在更新操作期间执行某些代码。
总之,理解和正确使用触发器上下文变量是编写有效和有条件的触发器代码的关键。
5.2.3 最佳实践和常见陷阱
编写触发器时,遵循一些最佳实践可以确保你的代码既有效又易于维护。同时,避免常见的陷阱会确保你的触发器不会导致意外的行为或性能问题。
最佳实践
One Trigger per Object (一个对象一个触发器):
避免为同一对象编写多个触发器。相反,为一个特定的sObject创建一个触发器,并在此触发器中调用类和方法来执行逻辑。这使得触发器逻辑更易于维护并且顺序更可预测。
trigger AccountTrigger on Account (before insert, after insert) {
if (Trigger.isBefore) {
AccountHandler.beforeInsert(Trigger.new);
}
if (Trigger.isAfter) {
AccountHandler.afterInsert(Trigger.new);
}
}
Bulkify Your Code (代码批量化):
总是假设触发器会处理多条记录。避免在循环中进行SOQL查询或DML操作。
List<Account> accountsToUpdate = new List<Account>();
for(Account a : Trigger.new) {
// 逻辑操作...
accountsToUpdate.add(a);
}
update accountsToUpdate;
Avoid Recursive Triggers (避免递归触发器):
确保触发器不会因为它自己的逻辑而再次触发。你可以使用静态变量来检查触发器是否已经执行过。
public class TriggerHelper {
public static Boolean isTriggerExecuted = false;
}
在触发器中:
if (!TriggerHelper.isTriggerExecuted) {
TriggerHelper.isTriggerExecuted = true;
// 触发器逻辑...
}
Use Helper Classes (使用帮助类):
将逻辑移动到帮助类中,以保持触发器简洁并易于测试。
常见陷阱
SOQL Queries Inside Loops (循环内的SOQL查询):
在循环内部进行SOQL查询会迅速耗尽你的SOQL限制。这是导致governor限制错误的常见原因。
Not Testing with Bulk Data (不使用批量数据进行测试):
当只测试少量数据时,触发器可能正常工作。但是,当处理大量数据时,可能会遇到性能问题或限制错误。
Not Considering Order of Execution (未考虑执行顺序):
在Salesforce中,存在一个定义好的执行顺序,例如先执行验证规则,然后执行触发器,等等。不考虑这一点可能会导致触发器在意料之外的时间执行。
Hardcoding IDs (硬编码ID):
从一个环境迁移到另一个环境时,记录ID可能会改变。避免在代码中硬编码特定的ID。
遵循这些最佳实践和避免常见的陷阱将帮助确保你的触发器是高效,可靠和可维护的。
参考1:【探索Apex开发之】 使用TriggerHandler,让你的代码逻辑更清晰
参考2:【探索Apex开发之】 使用TriggerHandler,让你的代码逻辑更清晰(使用Helper类)