LeadConvert的Apex负载字段缺失原因排查及修改方法
Lead Convert触发的Apex Webhook负载字段缺失问题
问题描述
针对Lead的Convert操作编写了after update触发器,调用Webhook发送JSON负载。开发环境中负载包含完整的Lead字段(含Id),但在第三方Salesforce账户中,负载仅保留少量字段,大量字段(包括Id)缺失。
触发器原代码:
trigger WebhookSenderTriggerLeadConvert on Lead (after update) { if (Trigger.new.size() == 1) { if (Trigger.old[0].isConverted == false && Trigger.new[0].isConverted == true) { if (Trigger.new[0].ConvertedAccountId != null) { String url = 'https://mydomain.io'; String content = WebhookSender.jsonContent(Trigger.new, Trigger.old); WebhookSender.callout(url, content); } } } }
WebhookSender原代码:
public class WebhookSender { public static String jsonContent(List<Object> triggerNew, List<Object> triggerOld) { String newObjects = '[]'; if (triggerNew != null) { newObjects = JSON.serialize(triggerNew); } String oldObjects = '[]'; if (triggerOld != null) { oldObjects = JSON.serialize(triggerOld); } String userId = JSON.serialize(UserInfo.getUserId()); String content = '{"new": ' + newObjects + ', "old": ' + oldObjects + ', "userId": ' + userId + '}'; return content; } @future(callout=true) public static void callout(String url, String content) { Http h = new Http(); HttpRequest req = new HttpRequest(); req.setEndpoint(url); req.setMethod('POST'); req.setHeader('Content-Type', 'application/json'); req.setHeader('Authorization', 'someKey'); req.setBody(content); if (!Test.isRunningTest()) {h.send(req);} } public static Map<String, Object> ParseRequest(RestRequest req) { String body = req.requestBody.toString(); Map<String, Object> data = (Map<String, Object>) JSON.deserializeUntyped(body); return data; } }
原因分析
- 触发器上下文字段限制:Salesforce触发器的
Trigger.new和Trigger.old仅包含实际被修改的字段及少量系统字段。Lead Convert操作中,第三方环境仅标记IsConverted、ConvertedAccountId等核心转换字段为修改状态,因此上下文变量仅携带这些字段,不会包含未修改的其他字段。 - 直接序列化上下文的局限性:JSON序列化
Trigger.new/old时,只会序列化上下文变量中存在的字段,无法自动补充未被修改的字段内容。
解决方案
通过显式查询获取完整的Lead记录(新旧状态),替代直接使用触发器上下文变量进行序列化。
方案1:仅获取转换后的完整新记录
如果不需要转换前的完整旧记录,修改原触发器即可:
trigger WebhookSenderTriggerLeadConvert on Lead (after update) { if (Trigger.new.size() == 1) { Lead oldLead = Trigger.old[0]; Lead newLead = Trigger.new[0]; if (!oldLead.isConverted && newLead.isConverted && newLead.ConvertedAccountId != null) { // 显式查询转换后的完整Lead记录,列出所有需要的字段 List<Lead> fullNewLeads = [ SELECT Id, Name, Email, Phone, Company, ConvertedAccountId, ConvertedContactId, ConvertedOpportunityId, IsConverted FROM Lead WHERE Id = :newLead.Id ]; // 使用Trigger.old的Id查询记录(注意:此时数据库中已为转换后状态) List<Lead> fullOldLeads = [ SELECT Id, Name, Email, Phone, Company FROM Lead WHERE Id = :oldLead.Id ]; String url = 'https://mydomain.io'; String content = WebhookSender.jsonContent(fullNewLeads, fullOldLeads); WebhookSender.callout(url, content); } } }
方案2:同时获取转换前后的完整记录
如果需要转换前的完整旧记录,需通过before update触发器缓存旧状态:
- 新建缓存类:
public class LeadConvertCache { public static List<Lead> oldFullLeads; }
- 新增
before update触发器:
trigger LeadConvertBeforeTrigger on Lead (before update) { if (Trigger.new.size() == 1) { Lead oldLead = Trigger.old[0]; if (!oldLead.isConverted && Trigger.new[0].isConverted) { // 查询并缓存转换前的完整Lead记录 LeadConvertCache.oldFullLeads = [ SELECT Id, Name, Email, Phone, Company FROM Lead WHERE Id = :oldLead.Id ]; } } }
- 修改原
after update触发器:
trigger WebhookSenderTriggerLeadConvert on Lead (after update) { if (Trigger.new.size() == 1) { Lead newLead = Trigger.new[0]; if (newLead.isConverted && newLead.ConvertedAccountId != null && LeadConvertCache.oldFullLeads != null) { // 查询转换后的完整Lead记录 List<Lead> fullNewLeads = [ SELECT Id, Name, Email, Phone, Company, ConvertedAccountId, ConvertedContactId, IsConverted FROM Lead WHERE Id = :newLead.Id ]; String url = 'https://mydomain.io'; String content = WebhookSender.jsonContent(fullNewLeads, LeadConvertCache.oldFullLeads); WebhookSender.callout(url, content); } } }
注意事项
- 必须明确列出需要查询的字段,避免使用
SELECT *,这是Salesforce的最佳实践,能提升查询性能并避免字段权限问题。 - 可将WebhookSender类的
jsonContent方法参数类型改为List<SObject>,使其更通用,原List<Object>也可兼容。
内容的提问来源于stack exchange,提问作者Jason
相关产品推荐
相关产品推荐

