Salesforce Apex Best Practices【写作中】
2023年09月08日
文章浏览:281
需求:
从Java或者C#(包换任何传统编程语言)转行到Salesforce开发的程序员的习惯性思维需要打破,
云计算机(简单点说,就是租赁),那么服务器的性能最大化,负荷最优就是我们需要考虑的问题。为了性能和负荷的最优,所以才会有Salesforce比较独特的【Apex Governor Limits】这个限制。

在这里我就来讲一下关于Apex代码的编写思维。



最佳实践1。批量处理数据

如果我们在Apex代码中创建数据,那么肯定是【一次提交多条数据】比【多次提交一条数据】,性能更优化。

比如,我们有下面的示例代码

trigger accountTestTrggr on Account (before insert, before update) {
 
   //这里的代码,每次只处理一条数据,从Trigger.new中取出第一条数据。
   //但是如果我们使用DataLoader或者另外的方式导入多条Account数据的时候,
   //除了第一条数据以外的数据,就不可能被执行到。
   //所以这个示例代码,就是有问题的代码。
   Account acct = Trigger.new[0];
   List<Contact> contacts = [select id, salutation, firstname, lastname, email
              from Contact where accountId = :acct.Id];
    
}


下面的代码,就是正常的Trigger的写法。

※当然了,正常情况下我们不会直接在Trigger里面直接写逻辑代码,那会非常不容易维护。

我们会通过TriggerHandler的方法来执行具体的逻辑代码。

大家可以参考下面的文章

【探索Apex开发之】 使用TriggerHandler,让你的代码逻辑更清晰

 http://salesforcegogogo.com/BlogsItem.aspx?id=83 

trigger accountTestTrggr on Account (before insert, before update) {
 
   List<String> accountNames = new List<String>{};
  
   //因为Trigger.new是一个数据的集合,最多会有200条数据,
   //下面的写法就是从这个集合里面循环取得数据
   for(Account a: Trigger.new){
      //下面更新Description的值
      a.Description = a.Name + ':' + a.BillingState
   }
    
}
最佳实践2。避免在循环内执行SOQL查询,或者DML操作(数据的增删改操作)


下面的示例代码,新人是最容易犯的问题。

在For循环中更新数据

(我以前有时候也这么写,但我会明确写下备注,List变量最多只有1条数据。)

而且这样的写法,会被别人视为不专业。所以千万不能在For循环进行DML操作。


下面是关于SOQL查询和DML操作的数量限制,仅供参考。

DescriptionSynchronous LimitAsynchronous Limit
Total number of SOQL queries issued1100200
Total number of DML statements issued2150150


下面是示例代码(错误的写法)

trigger accountTestTrggr on Account (before insert, before update) {
 
   //下面的示例代码,遍历一个List类型的变量(Trigger.new)
   for(Account a: Trigger.new) {
           
      //THIS FOLLOWING QUERY IS INEFFICIENT AND DOESN'T SCALE
      //Since the SOQL Query for related Contacts is within the FOR loop, if this trigger is initiated
      //with more than 100 records, the trigger will exceed the trigger governor limit
      //of maximum 100 SOQL Queries.
      
      
      //下面的查询代码,是非常没有效率, 每次仅仅查询1条数据。
      //由于查询代码在For循环中,所以如果Trigger.new的数据超过100条,
      //那么这个accountTestTrggr就会马上出异常,而导致所有数据操作回滚。
      List<Contact> contacts = [select id, salutation, firstname, lastname, email
                        from Contact where accountId = :a.Id];
       
      for(Contact c: contacts) {
         System.debug('Contact Id[' + c.Id + '], FirstName[' + c.firstname + '],
                                         LastName[' + c.lastname +']');
         c.Description=c.salutation + ' ' + c.firstName + ' ' + c.lastname;
          
         //下面的更新代码,也是类似,因为在For循环中
         //每次更新一次数据,可用的DML操作数量就减1,那就是说,如果Trigger.new的数据超过150条,
         //那么这个accountTestTrggr就会马上出异常,而导致所有数据操作回滚。
         //但是大家知道,在DML操作异常之前,SOQL的执行数量就已经达到极限值了。所以根本就不可能执行到150次DML操作
         update c;
      }      
   }
} 


讲解了错误的写法之后,我们再来看一下正常的写法


trigger accountTestTrggr on Account (before insert, before update) {

  //首先,在accountTestTrggr的最前面,把所有需要更新的数据先取出来,放到一个List变量中。
  //大家看到了,Where条件里面,我们指定了ID IN 这个条件。
  //IN 这个条件的值是,Trigger.newMap.keySet(),这个KeySet方法能够把Map变量里面所有的ID给取出来
  //所以在这里,我们只执行一次SOQL查询。那么执行SOQL查询后,
  //我们还有99次 SOQL查询可以使用。
  //不当家不知柴米贵,就是类似的道理。
  List<Account> accountsWithContacts = [select id, name, (select id, salutation, description,
                                                                firstname, lastname, email from Contacts)
                                                                from Account where Id IN :Trigger.newMap.keySet()];
     
  List<Contact> contactsToUpdate = new List<Contact>{};
  //下面的代码,在For循环中,修改每一条数据的值,最后把修改完的值再放入到contactsToUpdate这个变量里面。
  for(Account a: accountsWithContacts){
     // Use the child relationships dot syntax to access the related Contacts
     for(Contact c: a.Contacts){
      System.debug('Contact Id[' + c.Id + '], FirstName[' + c.firstname + '], LastName[' + c.lastname +']');
      c.Description=c.salutation + ' ' + c.firstName + ' ' + c.lastname;
      contactsToUpdate.add(c);
     }       
   }
       
   //Now outside the FOR Loop, perform a single Update DML statement.
   //最后,所以我们来更新修改过的Contact数据。
   //因为我们这个修改数据的操作,是在Loop循环外的,所以只占用一次DML操作,那么在accountTestTrggr执行完,
   //我们只占用了一次SOQL执行数量,和一次DML执行数量,那是相当的节省。对吧
   update contactsToUpdate;
}


最佳实践3。查询大量数据


下面还是Apex Governor Limits里面的限制项。

一次处理,我们最多只能从Salesforce上查询到5万条数据。

如果超过这个数据量,那么程序就直接抛出异常来结束程序运行。

DescriptionSynchronous LimitAsynchronous Limit
Total number of records retrieved by SOQL queries50,00050,000


TODO








所有的参考文章

 https://developer.salesforce.com/ja/wiki/apex_code_best_practices 

 https://www.salesforceben.com/12-salesforce-apex-best-practices/ 

 https://sfdclesson.com/2022/06/18/10-best-practices-for-apex-code/ 




关注 收藏
2023年09月08日

Trigger里最好不要写入逻辑,trigger只处理event, 将逻辑写到一个ApexClass, 比如*Handler.cls中。

回复
yusizhong 回复 jowell.qiao 是的是的,用TriggerHander。正常的Trigger里面是不能写具体的处理代码的,这个非常同意。哈哈
回复