Salesforce Apex超级徽章任务代码报错:List索引越界求助
问题背景
备考首个Salesforce超级徽章,在「Automate record creation」任务中编写了Case触发器及MaintenanceRequestHelper辅助类,意图实现:当Case状态从非Closed改为Closed且类型为Repair或Routine Maintenance时,自动创建维护请求记录。执行时触发System.ListException: List index out of bounds: 1异常,异常位于MaintenanceRequestHelper类的requestDue方法第64行。
原代码
Trigger Helper代码
public with sharing class MaintenanceRequestHelper { public static void createMaintenanceRequests(List<Case> newData, Map<Id, Case> oldData) { Set<Id> casesIds = new Set<Id>(); for(Case c : newData){ if(oldData.get(c.Id).Status != 'Closed' && c.Status == 'Closed'){ if(c.Type == 'Repair' || c.Type == 'Routine Maintenance'){ casesIds.add(c.Id); } } } Double minMaintenanceCycle = requestDue(casesIds); Integer daysToAdd = Math.round(minMaintenanceCycle); Date today = System.today(); List<Case> newCases = new List<Case>(); for(Case cc : [SELECT Id, ParentId, Vehicle__c, Vehicle__r.Name, (SELECT Equipment__c, Maintenance_Request__c, Quantity__c FROM Equipment_Maintenance_Items__r) FROM Case WHERE Id IN :casesIds]){ Case nc = new Case(); nc.ParentId = cc.Id; nc.Status = 'New'; nc.Subject = 'Maintenance Request for ' + cc.Vehicle__r.Name; nc.Type = 'Routine Maintenance'; nc.Vehicle__c = cc.Vehicle__c; for (Equipment_Maintenance_Item__c eq : cc.Equipment_Maintenance_Items__r) { Equipment_Maintenance_Item__c newEq = new Equipment_Maintenance_Item__c(); newEq.Equipment__c = eq.Equipment__c; newEq.Maintenance_Request__c = eq.Maintenance_Request__c; newEq.Quantity__c = eq.Quantity__c; nc.Equipment_Maintenance_Items__r.add(newEq); } nc.Date_Reported__c = today; nc.Date_Due__c = today.addDays(daysToAdd); newCases.add(nc); } try { insert newCases; } catch (DMLException e) { System.debug(e); } } public static Double requestDue(Set<Id> validIds){ List<Case> cases = [SELECT (SELECT Equipment__c, Maintenance_Request__c, Quantity__c FROM Equipment_Maintenance_Items__r) FROM Case WHERE Id IN :validIds]; Set<Id> equipIds = new Set<Id>(); for (Case c : cases) { for (Equipment_Maintenance_Item__c emi : c.Equipment_Maintenance_Items__r) { equipIds.add(emi.Equipment__c); } } List<Double> maintenanceCycles = new List<Double>(); List<Product2> equipmentList = [SELECT Maintenance_Cycle__c FROM Product2 WHERE Id IN :equipIds]; for (Product2 p : equipmentList) { maintenanceCycles.add(p.Maintenance_Cycle__c); } maintenanceCycles.sort(); return maintenanceCycles[0]; } }
Trigger代码
trigger MaintenanceRequest on Case (before update, after update) { if(Trigger.isUpdate && Trigger.isAfter){ MaintenanceRequestHelper.createMaintenanceRequests(Trigger.New, Trigger.OldMap); } }
错误信息
There was an unexpected error in your org which is preventing this assessment check from completing: System.DmlException: Update failed. First exception on row 0 with id 5008b00002KYlQbAAL; first error: CANNOT_INSERT_UPDATE_ACTIVATE_ENTITY, MaintenanceRequest: execution of AfterUpdate caused by: System.ListException: List index out of bounds: 1 Class.MaintenanceRequestHelper.requestDue: line 64, column 1 Class.MaintenanceRequestHelper.createMaintenanceRequests: line 13, column 1 Trigger.MaintenanceRequest: line 3, column 1: []
原因分析
- 直接触发点:
requestDue方法中,当maintenanceCycles列表为空时,执行return maintenanceCycles[0]会触发索引越界异常。错误信息中显示的索引1为行号对应偏差,本质是列表无元素时访问索引导致的异常。 - 触发场景:
- 符合条件的Case未关联任何
Equipment_Maintenance_Item__c记录,导致equipIds为空集合,查询Product2返回空列表,maintenanceCycles无元素。 - 关联的
Equipment_Maintenance_Item__c对应的Product2记录中,Maintenance_Cycle__c字段为空值,添加到列表时未做过滤,最终列表无有效数值。
- 符合条件的Case未关联任何
- 额外隐患:
createMaintenanceRequests方法中未判断casesIds是否为空,直接调用requestDue,会导致无意义的查询和异常触发。
解决建议
1. 处理空列表场景,避免索引越界
修改requestDue方法,先判断maintenanceCycles是否为空,返回默认值或抛出明确提示(根据业务需求选择):
public static Double requestDue(Set<Id> validIds){ List<Case> cases = [SELECT (SELECT Equipment__c, Maintenance_Request__c, Quantity__c FROM Equipment_Maintenance_Items__r) FROM Case WHERE Id IN :validIds]; Set<Id> equipIds = new Set<Id>(); for (Case c : cases) { for (Equipment_Maintenance_Item__c emi : c.Equipment_Maintenance_Items__r) { equipIds.add(emi.Equipment__c); } } List<Double> maintenanceCycles = new List<Double>(); List<Product2> equipmentList = [SELECT Maintenance_Cycle__c FROM Product2 WHERE Id IN :equipIds]; for (Product2 p : equipmentList) { // 过滤空值,避免添加无效数据 if(p.Maintenance_Cycle__c != null){ maintenanceCycles.add(p.Maintenance_Cycle__c); } } if(maintenanceCycles.isEmpty()){ // 返回默认维护周期(比如7天,根据业务要求调整) return 7.0; // 或者如果不需要创建请求,可返回null,后续逻辑判断 // return null; } maintenanceCycles.sort(); return maintenanceCycles[0]; }
2. 前置判断,避免无意义执行
在createMaintenanceRequests方法中,先判断casesIds是否为空,再执行后续逻辑:
public static void createMaintenanceRequests(List<Case> newData, Map<Id, Case> oldData) { Set<Id> casesIds = new Set<Id>(); for(Case c : newData){ if(oldData.get(c.Id).Status != 'Closed' && c.Status == 'Closed'){ if(c.Type == 'Repair' || c.Type == 'Routine Maintenance'){ casesIds.add(c.Id); } } } // 无符合条件的Case时直接返回 if(casesIds.isEmpty()){ return; } Double minMaintenanceCycle = requestDue(casesIds); // 如果requestDue返回null,说明无有效维护周期,跳过创建 if(minMaintenanceCycle == null){ return; } Integer daysToAdd = Math.round(minMaintenanceCycle); Date today = System.today(); List<Case> newCases = new List<Case>(); for(Case cc : [SELECT Id, ParentId, Vehicle__c, Vehicle__r.Name, (SELECT Equipment__c, Maintenance_Request__c, Quantity__c FROM Equipment_Maintenance_Items__r) FROM Case WHERE Id IN :casesIds]){ // 无关联设备时跳过创建 if(cc.Equipment_Maintenance_Items__r.isEmpty()){ continue; } Case nc = new Case(); nc.ParentId = cc.Id; nc.Status = 'New'; nc.Subject = 'Maintenance Request for ' + cc.Vehicle__r.Name; nc.Type = 'Routine Maintenance'; nc.Vehicle__c = cc.Vehicle__c; for (Equipment_Maintenance_Item__c eq : cc.Equipment_Maintenance_Items__r) { Equipment_Maintenance_Item__c newEq = new Equipment_Maintenance_Item__c(); newEq.Equipment__c = eq.Equipment__c; newEq.Maintenance_Request__c = eq.Maintenance_Request__c; newEq.Quantity__c = eq.Quantity__c; nc.Equipment_Maintenance_Items__r.add(newEq); } nc.Date_Reported__c = today; nc.Date_Due__c = today.addDays(daysToAdd); newCases.add(nc); } try { insert newCases; } catch (DMLException e) { System.debug(e); } }
3. 业务数据校验
确保测试用的Case关联了有效的Equipment_Maintenance_Item__c记录,且对应的Product2记录的Maintenance_Cycle__c字段已设置数值。
内容的提问来源于stack exchange,提问作者Rafael Moraes

