我在删除触发器之前运行Apex Job并发现通过Salesforce界面删除单个Campaign需要大约34秒,并且在删除Campaign时Apex Job已完成运行。当我使用VisualForce页面在相同数量的记录(15,000)上运行相同的Apex作业时,Apex Job排队并在VisualForce页面完成后运行。
在此屏幕截图中,第一个作业使用VisualForce排队,第二个和第三个作业使用触发器排队:
正如您所看到的,虽然相同的Apex作业在使用“触发器”排队时处理相同数量的记录(15,000),但不会创建任何批次,并且“提交”和“已完成”日期完全不同。
Apex Job在触发器中排队:
trigger DeleteChilds on Campaign (before delete) {
public static final Integer MAX_DELETED = 500;
Set<ID> ids = new Set<Id>();
List<Parent__c> objs = new List<Parent__c>();
for(Campaign c : Trigger.old)
ids.add(c.Id);
objs = [SELECT Id FROM Parent__c WHERE Campaign__c IN :ids];
ids = new Set<Id>();
for(Parent__c s : objs)
ids.add(s.Id);
Integer childCount = [SELECT count() FROM Childs__c WHERE Parent__c IN :ids];
if(childCount < MAX_DELETED){
List<Childs__c> childs = [SELECT Id FROM Childs__c WHERE Parent__c IN :ids];
delete childs;
} else {
String deleteQuery = 'SELECT Id FROM Childs__c WHERE ';
for(ID id : ids){
deleteQuery += String.format(' Parent__c = \'\'{0}\'\' OR', new String[] {id});
}
if(deleteQuery.endsWith('OR')){
deleteQuery = deleteQuery.substring(0, deleteQuery.length() - 2);
}
BatchDeleteChilds batch = new BatchDeleteChilds();
batch.deleteQuery = deleteQuery;
ID batchId = Database.executeBatch(batch);
}
delete objs;
}
这是Apex工作:
global class BatchDeleteChilds implements Database.Batchable<sObject> {
public String deleteQuery;
global Database.QueryLocator start(Database.BatchableContext context){
return Database.getQueryLocator(deleteQuery);
}
global void execute(Database.BatchableContext context, List<sObject> records){
delete records;
DataBase.emptyRecycleBin(records);
}
global void finish(Database.BatchableContext context){
}
}
有没有其他人经历过这样的事情?
谢谢,
答案 0 :(得分:2)
你正在寻找一个你可能永远不会赢的竞争条件。已删除的父对象将在批处理作业执行时提交,这会使数据库中从子节点到父节点的查找为空。因此,传递给批处理的查询将没有记录。
我不知道推动此方法的设计决策,但还有其他选项可用于批量删除子记录。最简单的方法是让孩子与父母的关系成为主要细节。使用此类关系会自动删除子记录。
其次,您可以使用visualforce页面覆盖父对象的删除按钮。然后,控制器将对子项进行计数,并决定是否启动批处理以删除它们。然后让批处理等待删除父对象,直到它完成方法。