Salesforce Apex作业未在触发器中异步运行
我在删除前触发器中运行Apex作业,注意到通过Salesforce界面删除单个活动大约需要34秒,删除活动时Apex作业已完成运行。当我使用VisualForce页面在相同数量的记录(15000)上运行相同的Apex作业时,Apex作业将排队,并在VisualForce页面完成后运行 在此屏幕截图中,第一个作业使用VisualForce排队,第二个和第三个作业使用触发器排队: 正如您所看到的,虽然相同数量的记录(15000条)在使用触发器排队时由相同的Apex作业处理,但没有创建和提交批次,完成日期也有很大不同 Apex作业在触发器中排队:Salesforce Apex作业未在触发器中异步运行,salesforce,Salesforce,我在删除前触发器中运行Apex作业,注意到通过Salesforce界面删除单个活动大约需要34秒,删除活动时Apex作业已完成运行。当我使用VisualForce页面在相同数量的记录(15000)上运行相同的Apex作业时,Apex作业将排队,并在VisualForce页面完成后运行 在此屏幕截图中,第一个作业使用VisualForce排队,第二个和第三个作业使用触发器排队: 正如您所看到的,虽然相同数量的记录(15000条)在使用触发器排队时由相同的Apex作业处理,但没有创建和提交批次,完
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;
}
在活动中触发DeleteChilds(删除前){
公共静态最终整数MAX_DELETED=500;
集合ID=新集合();
List objs=new List();
对于(活动c:Trigger.old)
添加(c.Id);
objs=[从父项中选择Id,其中活动位于:Id];
ids=新集合();
用于(父对象:objs)
添加(s.Id);
整数childCount=[从Childs__c中选择count(),其中父项在:id中];
if(已删除的子计数<最大值){
List childs=[从childs_uuuc中选择Id,其中Parent_uuc IN:Id];
删除child;
}否则{
String deleteQuery='从Childs__cwhere'中选择Id';
用于(ID:ids){
deleteQuery+=String.format('Parent\uu c=\'\'\'{0}\'\'或',新字符串[]{id});
}
if(deleteQuery.endsWith('OR')){
deleteQuery=deleteQuery.substring(0,deleteQuery.length()-2);
}
BatchDeleteChilds batch=新的BatchDeleteChilds();
batch.deleteQuery=deleteQuery;
ID batchId=数据库.executeBatch(批处理);
}
删除obj;
}
这是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){
}
}
全局类BatchDeleteChilds实现数据库。可批处理{
公共字符串查询;
global Database.QueryLocator启动(Database.BatchableContext上下文){
返回Database.getQueryLocator(deleteQuery);
}
全局void execute(Database.BatchableContext上下文,列表记录){
删除记录;
数据库.emptyRecycleBin(记录);
}
全局void完成(Database.BatchableContext上下文){
}
}
还有其他人经历过这样的事情吗
谢谢,你看到的是一种可能永远不会赢的比赛状态。已删除的父对象将在批处理作业执行时提交,这将取消数据库中从子对象到父对象的查找。因此,传递到批处理中的查询将没有记录
- 预删除子项:(名称='example',父项='123')
- 后期删除(批处理前)子项:(名称='example',父项\uuu c=null)
其次,您可以使用visualforce页面覆盖父对象的delete按钮。然后,控制器将对这些子项进行计数,并决定是否启动批处理来删除它们。然后让批处理过程等待删除父对象,直到其完成方法。有趣的问题。有没有可能在调试登录的情况下运行并共享结果?可能有助于识别可能未作为错误报告给批处理上下文的问题。另外,最好在删除后的上下文中运行它,不是吗?以防活动无法删除。这样就不会丢失子记录。将触发器更改为在删除后运行会导致父对象的活动\uuu\c字段为空,因为该活动已被删除。这不会导致删除,因为[SELECT Id FROM Parent__cwhere Campaign__cin:ids]不会返回任何结果。我决定使用Apex作业的原因是响应接口。虽然从接口中删除父对象将导致删除所有子对象,但页面加载需要35秒才能加载10000个子对象。我明白了,覆盖删除按钮听起来是个不错的选择。如果这对你有效,请告诉我。