是否有任何改进代码性能的余地?

Is there any scope to improve my code performance?

提问人:bnthsrikanth 提问时间:11/15/2023 最后编辑:bnthsrikanth 更新时间:11/16/2023 访问量:43

问:

我有一个 Salesforce Apex REST 服务 (LeadService),它以 JSON 格式处理传入的潜在客户。此外,我正在寻找增强错误处理并使代码更易于维护的方法。为优化批量更新插入过程和增强整体代码结构提供建议或改进

@RestResource(urlMapping='/api/lead')
global class Service {
@HttpPost
global static string createdata(){
   
    RestResponse res = Restcontext.response;
    String requestBody = RestContext.request.requestBody.toString();
    try {   
        // Deserialize JSON data into a list of LeadDataDeserializer objects
        List<LeadDataDeserializer> externalLeads = (List<LeadDataDeserializer>)
            JSON.deserializeStrict(requestBody, List<LeadDataDeserializer>.class);            
        // Transform LeadDataDeserializer objects into Lead data
        List<Lead> students = new List<Lead>();
        for(LeadDataDeserializer info : externalLeads) {
            Lead t_leads = setLeadFields(info);
            t_leads.company='Test Company';
            students.add(t_leads);
        }
        if(students.isEmpty()){
            res.statusCode=400;
            return 'Empty list';
            
           
        }
        else{
            List<Response> responseretn=new List<Response>();
            Database.UpsertResult[] srList = Database.upsert(students, Lead.External_Id__c, false);
            // Process upsert results if needed
            Integer i=0;
            for(Database.UpsertResult upResult:srList){
                if(upResult.isSuccess()){
                    responseretn.add(new Response(upResult.getId(),true,students[i].MobilePhone));
                }
                else{
                    System.debug(upResult.getErrors());
                    responseretn.add(new Response(upResult.getId(),false,students[i].MobilePhone));
                }
                i+=1;
            }
        
            String jsonReqBody=JSON.serialize(responseretn);
            res.statusCode = 201;
            return jsonReqBody;
            
           
                            
        }
        
    } catch(Exception e) {
        // Handle exceptions
        res.Statuscode = 500;
        return 'Internal Server Error';

        
    }
}
//Response wrapper to return
public class Response{
    public string leadId{get;set;}
    public boolean isSuccess{get;set;}
    public string mobilePhone{get;set;}
    
    public Response(String leadId,Boolean isSuccess,String mobilePhone){
        this.leadId=leadId;
        this.isSuccess=isSuccess;
        this.mobilePhone=mobilePhone;
    }
}

public static Lead setLeadFields(LeadDataDeserializer info){
    Lead extLead=new Lead();
    extLead.LastName=info.Name;
    extLead.CountryCode__c=info.countryCode; 
    extLead.MobilePhone=info.phoneNumber;
    extLead.mx_WhatsApp_Number__c=extLead.MobilePhone;
    extLead.mx_IP_Address__c=info.ipAddress;
    extLead.External_Id__c=extLead.MobilePhone;
    if(info.leadStage!=null){
        extLead.Status=info.leadStage;
    }
    if(info.campaignName!=null){
        extLead.mx_Campaign_Name__c=info.campaignName;
    }
    if(info.campaignSource!=null){
        extLead.SourceCampaign__c=info.campaignSource;
    }

    //20 more if conditions with null check like above (serializeddata.field!=null)
   
    return extLead;
}}

我使用多个 if 语句来处理仅包含具有值的字段,并且如果来自集成的值为空,则不会覆盖上一个记录值

如何有效地处理这个问题?

集成 Apex Salesforce-Lightning SOQL

评论


答:

1赞 eyescream 11/15/2023 #1
if(students.isEmpty()){
   res.statusCode=400;
   return 'Empty list';
}

这有点晚了。性能不会有太大变化,但从逻辑上讲,最好早点检查反序列化列表,然后返回,而不是在从中获取潜在客户之后。

我认为您不必返回字符串。您可以轻松返回,SF 将为您序列化。List<Response>

你想如何处理问题?尽你所能保存?您可以为任何问题插入帮助程序 sObject 并运行有关该问题的报告。或者使用带有“立即发布”的平台事件,以便一些监控系统甚至特殊的顶点触发器可以处理它们。

我可能会包括错误计数器,所以如果它是 100% 的失败率,则返回 201 以外的其他内容

如果它发送> 10K 行怎么办(否则副作用将导致> 10K dmls)......如果这是一个合理的问题,我可能会重写它以启动批处理作业(批处理可以获取范围并迭代它,它们并不总是必须从查询开始)。您可以和工作几乎完成的奖励点,SF 将为您做很多错误处理,而无需手动“保存点-尝试-捕获-回滚-插入任务或其他任何任务”implements Database.RaisesPlatformEvents

至于实际的映射代码......它不是很好,但也不是很糟糕。对于空检查,你可能觉得它有点太幼稚了 - 因为某些变量会更好,这取决于源生成的 JSON。String.isNotBlank

我会将源-目标字段映射保存在其他地方(自定义设置?自定义元数据?),这样您就不必在每次添加新字段时重新编译、部署等。

如果你真的觉得很奇特,你可以阅读有关JSON.serialize的信息,并带有跳过空值的参数(例如,你可以反序列化输入,在跳过空值的情况下将其序列化回来,第二次反序列化,干净)。或者盲目地根据输入设置所有字段,然后 sObject.getPopulatedFieldsAsMap 并遍历它们,检查什么是空的......但对于需要的东西来说,感觉有点太聪明了。有时简单是最有效的。


它甚至必须是自定义 REST API 吗?如果你能控制源格式,你可以考虑复合而不是标准api,减少工作量。看看我的 https://salesforce.stackexchange.com/a/274696/799(包括“allOrNone”标题)。正常的更新插入不能很好地处理多个记录,没错 - 但这已经足够接近了!

嗯......代码并不总是答案。如果您绝对确定标准 API 不会削减它 - 您知道可以通过 REST API 调用流吗?

====

编辑

这是一个很好的示例(您可以在“匿名执行”中运行它

public class Wrapper {
    public Boolean isActive;
    public String name;
    public String email;
    public String phone;
}

String text = '['+
        '  {'+
//      '    \"isActive\": false,'+
        '    \"name\": \"Blankenship Ryan\",'+
        '    \"email\": \"[email protected]\",'+
        '    \"phone\": \"+1 (803) 465-3324\"'+
        '  },'+
        '  {'+
        '    \"isActive\": false,'+
//      '    \"name\": \"Herring Blevins\",'+
        '    \"email\": \"[email protected]\",'+
        '    \"phone\": \"+1 (938) 592-2521\"'+
        '  },'+
        '  {'+
        '    \"isActive\": true,'+
        '    \"name\": \"Paige Holman\",'+
//      '    \"email\": \"[email protected]\",'+
        '    \"phone\": \"+1 (968) 576-3874\"'+
        '  },'+
        '  {'+
        '    \"isActive\": false,'+
        '    \"name\": \"Meadows Clemons\",'+
        '    \"email\": \"[email protected]\"'+ // removed comma here
//      '    \"phone\": \"+1 (806) 463-3276\"'+
        '  },'+
        '  {'+
        '    \"isActive\": true,'+
        '    \"name\": \"Shawna Holt\",'+
        '    \"email\": \"[email protected]\",'+
        '    \"phone\": \"+1 (956) 542-2138\"'+
        '  },'+
        '  {'+
//      '    \"isActive\": false,'+
//      '    \"name\": \"Tonya Britt\",'+
//      '    \"email\": \"[email protected]\",'+
//      '    \"phone\": \"+1 (845) 543-2721\"'+
        '  }'+
        ']';
System.debug(text);
List<Wrapper> wrappers = (List<Wrapper>) JSON.deserializeStrict(text, List<Wrapper>.class);
System.debug('nulls should show');
System.debug(wrappers);

List<Wrapper> wrappers2 = new List<Wrapper>();
for(Wrapper w : wrappers){
    String stripped = JSON.serialize(w, true);
    System.debug('should have no nulls: ' + stripped);
    Wrapper w2 = (Wrapper) JSON.deserialize(stripped, Wrapper.class);
    System.debug('but deserialized - they pop back: ' + w2);
}

反序列化才是问题所在,即使您的源系统不发送 null。

https://salesforce.stackexchange.com/questions/257158/json-serialize-is-it-possible-to-suppress-null-values-of-a-map 中有一些技巧,您可以使用或循环遍历潜在客户的 getPopulatedFieldsAsMap,并将它们复制到最终潜在客户,只有当它们不是 null 时才会进行更新插入......但这听起来有点聪明,你可读的 if 列表没有错。是的,这很无聊,也许可以从一些配置中读取......但它有效。

评论

0赞 bnthsrikanth 11/15/2023
感谢您的回答@eyescream我没有使用标准 api 或批处理 api,因为客户端等待响应,因此它会更新他们的中央数据库并想要自定义响应,而不是响应中的所有额外字段,您能否提供有关 json 技术的链接,以删除 null 或空的字段
0赞 bnthsrikanth 11/15/2023
而且@eyescream是 post 方法不支持自定义包装类列表,所以我已经序列化了响应,或者我们是否有任何其他方法可以发送自定义列表包装器响应
0赞 eyescream 11/16/2023
当你说“不支持包装器列表”时,你的意思是?如果将包装类标记为全局怎么办?global static List< Response> createdata(){