前往小程序,Get更优阅读体验!
立即前往
发布
社区首页 >专栏 >Salesforce学习 What is Trigger in Salesforce?

Salesforce学习 What is Trigger in Salesforce?

原创
作者头像
repick
修改2020-12-14 15:02:29
修改2020-12-14 15:02:29
81600
代码可运行
举报
文章被收录于专栏:SalesforceSalesforce
运行总次数:0
代码可运行

什么时触发器:

触发器是一个Apex代码,用于在操作记录之前或之后执行操作。

这些操作可以是:

触发器主要有两种类型:

Before Trigger:

用于在将记录的值保存到数据库之前对其进行更新或验证,然后再保存它。

After Trigger:

用于访问系统设置的字段值,并影响记录中的任何更改。换句话说,在这里一般用于更改其他Object的值。

Trigger Syntax:

代码语言:javascript
代码运行次数:0
复制
trigger TriggerName on ObjectName (trigger_events) {
    code_block
}  

trigger_events:可以指定一个或多个,用【,】分割。

  • before insert
  • before update
  • before delete
  • after insert
  • after update
  • after delete
  • after undelete

例:下边时【Account】Object的触发器写法例

代码语言:javascript
代码运行次数:0
复制
trigger AccountTrigger on Account (before insert, after insert, before update, after update, before delete, after delete, after undelete) {
    code_block
}

Trigger Context Variables

isInsert

Returns true if the trigger was fired due to an insert operation

isUpdate

Returns true if the trigger was fired due to an update operation

isDelete

Returns true if the trigger was fired due to a delete operation

isBefore

Returns true if the trigger has been fired before any record was saved

isAfter

Returns true if the trigger was fired after all records have been saved

isUndelete

Returns true if the trigger was fired after a record has been recovered from the Recycle Bin

new

Returns a list of new versions of the sObject records

newMap

A map of IDs to the new versions of the sObject records

old

Returns a list of old versions of the sObject records

oldMap

A map of IDs to the old versions of the sObject records

size

The total number of records in a trigger invocation, both old and new

一般有一下几种场景:

1.check:对画面输入项目进行相关check,也就是业务级别的check,如果是Validation级别的check,不是在Trigger里边实装,而是在【validationRules】里进行。

※validationRules相关做法,会在以后进行讲解。

2.插入更新当前Object,和相关联的Object

3.相关表权限的控制,比如可以实现AccountShare表的增删改。

4.对于各个User数据,进行权限控制,比如可以实现PermissionSetAssignment的增删改。

实战运用例:

例1:利用【Trigger.new】和【Trigger.oldMap】在触发器逻辑中可以判断出某个特定项目是否发生变更。

代码语言:javascript
代码运行次数:0
复制
trigger AccountTrigger on Account (before insert, after insert,
                                  before update, after update,
                                  before delete, after delete, after undelete) {
    // 例1:Trigger.new
    List<Account> accList = [SELECT Id,Name FROM Account WHERE AccountId IN : Trigger.new];
    // 例2:Trigger.isInsert
    Id personalAccRTId
       = Schema.SObjectType.Account.getRecordTypeInfosByDeveloperName().
       get('IndustriesIndividual').getRecordTypeId();
    Id corporationAccRTId
       = Schema.SObjectType.Account.getRecordTypeInfosByDeveloperName().
       get('IndustriesBusiness').getRecordTypeId();
    Set<Id> accountRTIdSet = new Set<Id> {personalAccRTId, corporationAccRTId};
    Boolean isInsert = Trigger.isInsert ? true : false;
    Boolean isUpdate = Trigger.isUpdate ? true : false;
    Boolean isDelete = Trigger.isDelete ? true : false;
    if (isUpdate) {
      for (Account acc : Trigger.new) {
          Account oldAccount;
          if (Trigger.oldMap.containsKey(acc.Id)) {
            oldAccount = Trigger.oldMap.get(acc.Id);
          }
          if (accountRTIdSet.contains(acc.RecordTypeId)) {
            if(oldAccount != null && acc.OwnerId != oldAccount.OwnerId) {
              // logic
            }
          }
      }
    }
 }

例2:利用【Trigger.isBefore】和【Trigger.isAfter】在触发器中特定场景下的处理,一般遵循一下规则:

更新当前Object的项目时用【Before】,更新其它关联Object项目时,用【After】

代码语言:javascript
代码运行次数:0
复制
trigger AccountTrigger on Account (before insert, after insert,
                                  before update, after update,
                                  before delete, after delete, after undelete) {
  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';
        }
    }
  } 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;
    }
  }
}

例3:利用触发器可以做check,错误信息也可以放在单独项目上,

代码语言:javascript
代码运行次数:0
复制
trigger AccountTrigger on Account (before insert, after insert,
                                  before update, after update,
                                  before delete, after delete, after undelete) {
    Id personalAccRTId
       = Schema.SObjectType.Account.getRecordTypeInfosByDeveloperName().
       get('IndustriesIndividual').getRecordTypeId();
    Id corporationAccRTId
       = Schema.SObjectType.Account.getRecordTypeInfosByDeveloperName().
       get('IndustriesBusiness').getRecordTypeId();
    Set<Id> accountRTIdSet = new Set<Id> {personalAccRTId, corporationAccRTId};
    if (Trigger.isBefore) {
        if (Trigger.isDelete) {
            for (Account currentAccount : Trigger.new) {
                if (accountRTIdSet.contains(currentAccount.RecordTypeId)) {
                    currentAccount.addError(System.Label.MC001);
                }
            }
        }
        if (Trigger.isUpdate) {
            for (Account acc : Trigger.new) {
                Account oldAccount;
                if (Trigger.oldMap.containsKey(acc.Id)) {
                    oldAccount = Trigger.oldMap.get(acc.Id);
                }
                if (accountRTIdSet.contains(acc.RecordTypeId)) {
                  if(oldAccount != null && acc.Name != oldAccount.Name) {
                      acc.Name.addError(System.label.MC002);
                  }
                }
            }
        }
    }
 }

所有ErrorMessage都可以定义在下边文件内。

CustomLabels.labels-meta.xml

代码语言:javascript
代码运行次数:0
复制
<?xml version="1.0" encoding="UTF-8"?>
<CustomLabels xmlns="http://soap.sforce.com/2006/04/metadata">
<labels>
    <fullName>MC001</fullName>
    <language>ja</language>
    <protected>false</protected>
    <shortDescription>MC089</shortDescription>
    <value>このデータは削除できません。</value>
</labels>
<labels>
    <fullName>MC002</fullName>
    <language>ja</language>
    <protected>false</protected>
    <shortDescription>MC089</shortDescription>
    <value>このデータは更新できません。</value>
</labels>
</CustomLabels>

例4:用户权限相关控制

代码语言:javascript
代码运行次数:0
复制
// 对于当前用户的权限,首先进行删除操作
List<PermissionSetAssignment> permissionSetList
                = [SELECT Id,PermissionSetId FROM PermissionSetAssignment
                                WHERE AssigneeId IN :('用户1的Id','用户2的Id')
                                AND PermissionSetId IN (SELECT Id
                                                      FROM PermissionSet
                                                     WHERE IsOwnedByProfile =false
                                                     AND Name IN :('一般管理者xx1','一般管理者xx2','一般管理者xx3'))];
Database.delete(permissionSetList);
// 权限表的登录
List<PermissionSetAssignment> pSetAssignmentObjList = new List<PermissionSetAssignment>();
// 权限set表取得权限Setid
Id generalManagerId = [select Id from PermissionSet where Name = :'一般管理者xxxxx'];
List<User> userList = [Select Id FROM User WHERE Name IN :('用户1','用户2')];
for (User user : userList) {
    PermissionSetAssignment pSetAssignmentObj = new PermissionSetAssignment();
    pSetAssignmentObj.PermissionSetId = generalManagerId;
    pSetAssignmentObj.AssigneeId = user.Id;
    pSetAssignmentObjList.add(pSetAssignmentObj);
}
Database.insert(pSetAssignmentObjList);

例5:不论是触发器还是ApexClass,利用【System.UserInfo】在代码里边可以直接取得当前登录用户的一般信息。

代码语言:javascript
代码运行次数:0
复制
// 当前用户的UserId
String loginUserId = UserInfo.getUserId();
// TimeZone取得
String tz = UserInfo.getTimeZone().getID();
// 当前用户绑定的ProfileId
String currentProfileId = UserInfo.getProfileId();

例子6:通过Handler对trigger进行封装,ApexClass中分发各种类型的触发器,使各个Object的触发器有更好的扩展性,和可读性,方便后期维护。

代码语言:javascript
代码运行次数:0
复制
public  with sharing abstract class TgrHdlExtender {
    public String strClassName;
    public void exec() {
        if(Trigger.new == null && Trigger.old == null) return;
        System.debug('[Execute Begin] ' + this.strClassName + ' : ' + Trigger.operationType);
        switch on Trigger.operationType {
            when BEFORE_INSERT  { this.beforeInsert  (Trigger.new); }
            when BEFORE_UPDATE  { this.beforeUpdate  (Trigger.old, Trigger.oldMap, Trigger.new, Trigger.newMap); }
            when BEFORE_DELETE  { this.beforeDelete  (Trigger.old, Trigger.oldMap); }
            when AFTER_INSERT   { this.afterInsert   (Trigger.new, Trigger.newMap); }
            when AFTER_UPDATE   { this.afterUpdate   (Trigger.old, Trigger.oldMap, Trigger.new, Trigger.newMap); }
            when AFTER_DELETE   { this.afterDelete   (Trigger.old, Trigger.oldMap); }
            when AFTER_UNDELETE { this.afterUndelete (Trigger.new, Trigger.newMap); }
        }
        System.debug('[Execute End] ' + this.strClassName + ' : ' + Trigger.operationType);
    }
    protected virtual void beforeInsert  (List<SObject> newList) { this.alertMsg(); }
    protected virtual void beforeUpdate  (List<SObject> oldList, Map<Id, SObject> oldMap, List<SObject> newList, Map<Id, SObject> newMap) { this.alertMsg(); }
    protected virtual void beforeDelete  (List<SObject> oldList, Map<Id, SObject> oldMap) { this.alertMsg(); }
    protected virtual void afterInsert   (List<SObject> newList, Map<Id, SObject> newMap) { this.alertMsg(); }
    protected virtual void afterUpdate   (List<SObject> oldList, Map<Id, SObject> oldMap, List<SObject> newList, Map<Id, SObject> newMap) { this.alertMsg(); }
    protected virtual void afterDelete   (List<SObject> oldList, Map<Id, SObject> oldMap) { this.alertMsg(); }
    protected virtual void afterUndelete (List<SObject> newList, Map<Id, SObject> newMap) { this.alertMsg(); }
    private void alertMsg(){
        System.debug('[Execute] method is not set.');
    }
}

Trigger类

代码语言:javascript
代码运行次数:0
复制
trigger OpportunityTrigger on Opportunity (before insert, after insert, before update, after update, before delete, after delete, after undelete) {
    new OpportunityTgrHdl().exec();
}

ApexClass:在Hdl类中写自己的逻辑业务。

代码语言:javascript
代码运行次数:0
复制
public with sharing class OpportunityTgrHdl extends TgrHdlExtender {
    public OpportunityTgrHdl() {
        if(String.isEmpty(this.strClassName)){
            Exception e = new DmlException();
            String[] lines = e.getStackTraceString().split('\n');
            for (Integer i = lines.size()-1; i >= 0; i--) {
                if(lines[i].startsWith('Class.')){
                    this.strClassName =  lines[i].substringBetween('Class.','.');
                }
            }
        }
	}
    public override void beforeInsert(List<SObject> newList) {
        // logic
    }
    public override void beforeUpdate(List<SObject> oldList, Map<Id, SObject> oldMap, List<SObject> newList, Map<Id, SObject> newMap) {
        // logic
    }
    public override void afterInsert(List<SObject> newList, Map<Id, SObject> newMap) {
        // logic
    }
    public override void afterUpdate(List<SObject> oldList, Map<Id, SObject> oldMap, List<SObject> newList, Map<Id, SObject> newMap) {
        // logic
    }
    public override void afterDelete(List<SObject> oldList, Map<Id, SObject> oldMap) {
        // logic
    }
}

总结及注意事项:

1. Trigger中不要使用batch去更新数据

2. Before Trigger中只对进入trigger的数据进行字段的更改,不要使用DML操作

3. After Trigger中对除本对象外的数据进行DML操作

4. 写Trigger一定要谨慎小心,避免数据循环进入trigger的情况发生

5. 尽量不要在Trigger逻辑复杂的对象上创建field update的workflow,因为workflow执行顺序在after trigger之后,所以workflow执行update之后,很容易导致trigger被二次调用。

6. Trigger.newMap和Trigger.oldMap都是Read-Only的,不可以在trigger中对其进行更改。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • Trigger Syntax:
  • Trigger Context Variables
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档