Salesforce APEX私有函数返回0而非预期值求助
问题原因与解决方案
核心原因
你写的getSumRevenueOnSchedule函数通过SOQL查询数据库,但在Before Insert/Update触发器的执行上下文里,新创建或修改的OpportunityLineItemSchedule记录还未被持久化到数据库中:
- 如果是Insert操作:数据库里完全没有这些新Schedule,SOQL返回空列表,总和自然是0。
- 如果是Update操作:SOQL只能查到更新前的旧数据,拿不到当前触发上下文里的新
Revenue值。
修复方案
必须把触发上下文里的newSchedules一起纳入计算,不能只依赖数据库查询。可以先将新记录按OpportunityLineItemId分组求和,再加上数据库中已存在的旧记录总和,得到完整的总金额。
修改后的代码示例:
public class OpportunityLineItemScheduleHandler { public static void handleBeforeInsertUpdate(List<OpportunityLineItemSchedule> newSchedules) { Set<Id> oppLineItemIds = new Set<Id>(); Map<Id, OpportunityLineItem> oppLineItems = new Map<Id, OpportunityLineItem>(); // 分组计算触发上下文里新Schedule的收入总和 Map<Id, Decimal> newScheduleRevenueSum = new Map<Id, Decimal>(); // 收集商机产品ID并累加新记录的收入 for (OpportunityLineItemSchedule schedule : newSchedules) { oppLineItemIds.add(schedule.OpportunityLineItemId); Decimal currentRevenue = schedule.Revenue == null ? 0 : schedule.Revenue; if (newScheduleRevenueSum.containsKey(schedule.OpportunityLineItemId)) { newScheduleRevenueSum.put(schedule.OpportunityLineItemId, newScheduleRevenueSum.get(schedule.OpportunityLineItemId) + currentRevenue); } else { newScheduleRevenueSum.put(schedule.OpportunityLineItemId, currentRevenue); } } // 查询对应的商机产品记录 oppLineItems.putAll([SELECT Id, Gross_Revenue_Calc__c FROM OpportunityLineItem WHERE Id IN :oppLineItemIds]); // 用聚合查询快速获取数据库中已存在的旧Schedule收入总和(排除当前触发的记录) Map<Id, AggregateResult> existingScheduleSumMap = new Map<Id, AggregateResult>([ SELECT OpportunityLineItemId, SUM(Revenue) totalRevenue FROM OpportunityLineItemSchedule WHERE OpportunityLineItemId IN :oppLineItemIds AND Id NOT IN :newSchedules GROUP BY OpportunityLineItemId ]); for (OpportunityLineItemSchedule schedule : newSchedules) { OpportunityLineItem oppLineItem = oppLineItems.get(schedule.OpportunityLineItemId); if (oppLineItem == null) continue; // 计算完整收入总和:新记录总和 + 数据库旧记录总和 Decimal totalRevenue = newScheduleRevenueSum.get(schedule.OpportunityLineItemId); AggregateResult existingSumResult = existingScheduleSumMap.get(schedule.OpportunityLineItemId); if (existingSumResult != null) { totalRevenue += (Decimal)existingSumResult.get('totalRevenue'); } System.debug(totalRevenue); if (totalRevenue > oppLineItem.Gross_Revenue_Calc__c) { schedule.addError('产品计划收入总和不能超过商机产品的毛收入。'); } } } }
额外注意点
- 用
AggregateResult做SOQL聚合查询比循环遍历求和更高效,尤其适合数据量较大的场景。 - 要判断
Revenue字段是否为null,避免空指针异常。 - Update场景下必须排除当前触发的记录ID,防止重复计算旧的
Revenue值。
内容的提问来源于stack exchange,提问作者shafi jan
相关产品推荐
相关产品推荐

