【问题标题】:Apex batch not executing all recordsApex 批处理未执行所有记录
【发布时间】:2013-01-10 17:34:45
【问题描述】:

我对 Apex 比较陌生,但我对正在创建的批处理作业有疑问。我正在尝试根据我公司的区域对齐插入 AccountTeamMember 记录。该代码似乎运行良好,但有一个缺陷:它只为每个用户插入 100 个 AccountTeamMember 记录(它应该接近 400,因为这是我在开发沙箱中加载的数量)。有谁知道我可以做些什么来为每个用户的所有帐户插入一个 AccountTeamMember 记录,而不是 400 个中的 100 个?是否与查询有关,包括父子关系和州长限制,因为它是偶数(100)?

以下是相关代码:

//list to hold new account teams
List<AccountTeamMember> acctMembers = new List<AccountTeamMember>();

//list to hold new account sharing rules
List<AccountShare> acctSharingRules = new List<AccountShare>();

global Database.querylocator start(Database.BatchableContext BC){
String query = 'SELECT (SELECT User__c FROM Territory_Users__r), (SELECT Account__c FROM Territory_Accounts__r) FROM Territory_Master__c';
return Database.getQueryLocator(query);}

global void execute(Database.BatchableContext BC, List<sObject> scope){

for (sObject s : scope) {
    Territory_Master__c tm = (Territory_Master__c) s;
    Territory_User__c[] userList = tm.getSObjects('Territory_Users__r');
    Territory_Account__c[] accountList = tm.getSObjects('Territory_Accounts__r');


    if (userList != null && accountList != null){
        for(Territory_User__c uu : userList){
            for(Territory_Account__c aa: accountList){
                AccountTeamMember addRecord = new AccountTeamMember();
                addRecord.AccountId = aa.Account__c;
                addRecord.TeamMemberRole = 'Sales Rep';
                addRecord.UserId = uu.User__c;
                acctMembers.add(addRecord);

                AccountShare addSharing = new AccountShare();
                addSharing.AccountId = aa.Account__c;
                addSharing.OpportunityAccessLevel = 'Read';
                addSharing.CaseAccessLevel = 'Read';
                addSharing.AccountAccessLevel = 'Edit';
                addSharing.UserOrGroupId = uu.User__c;
                acctSharingRules.add(addSharing);

            }
        }
    }
}

//DML
if(acctMembers.size() > 0){
    insert acctMembers;
}
if(acctSharingRules.size() > 0){
    insert acctSharingRules;
}
}

谢谢,

特雷

仅供参考:这是基于问题答案的最终结果:

global Database.querylocator start(Database.BatchableContext BC){
String query = 'SELECT Id FROM Territory_Master__c';
return Database.getQueryLocator(query);}

global void execute(Database.BatchableContext BC, List<sObject> scope){

for(sObject s : scope){
    Territory_Master__c tm = (Territory_Master__c) s;

    List<Territory_User__c> userList = [SELECT User__c FROM Territory_User__c WHERE Territory_Master__c = :tm.Id];
    List<Territory_Account__c> accountList = [SELECT Account__c FROM Territory_Account__c WHERE Territory_Master__c = :tm.Id];

    if (userList != null && accountList != null){
        for(Territory_User__c uu : userList){
                for(Territory_Account__c aa: accountList){
                AccountTeamMember addRecord = new AccountTeamMember();
                addRecord.AccountId = aa.Account__c;
                addRecord.TeamMemberRole = 'Sales Rep';
                addRecord.UserId = uu.User__c;
                acctMembers.add(addRecord);

                acctSharingRules.add(new AccountShare(
                    AccountId = aa.Account__c,
                    OpportunityAccessLevel = 'Read',
                    CaseAccessLevel = 'Read',
                    AccountAccessLevel = 'Edit',
                    UserOrGroupId = uu.User__c)
                );
            }
        }
    }
}

//DML
if(acctMembers.size() > 0){
    insert acctMembers;
}
if(acctSharingRules.size() > 0){
    insert acctSharingRules;
}
}

【问题讨论】:

    标签: salesforce apex-code force.com


    【解决方案1】:

    我怀疑您的子查询受到限制,您的工作是确保在继续下一条记录之前完成此记录。

    http://www.salesforce.com/us/developer/docs/api/Content/sforce_api_calls_soql_relationships.htm

    子查询结果与您可能需要的常规查询结果类似 如果有很多记录,则使用 queryMore() 检索所有记录 孩子们。例如,如果您对包含以下内容的帐户发出查询 子查询,您的客户端应用程序必须处理来自 子查询也是如此

    (示例是Java调用Salesforce,所以不要复制粘贴代码,试着理解这个概念。据我所知Apex没有这个queryMore方法,它只用于集成)

    选项 1

    很有趣,如果您将 for 循环更改为这样,理论上它应该可以工作:

    for(Territory_User__c uu : tm.getSObjects('Territory_Users__r')){
        for(Territory_Account__c aa: tm.getSObjects('Territory_Accounts__r'))
    

    那是因为 should automatically call their internal queryMore() 那样写的 for 循环。

    如果它不起作用(我没有测试过),你将不得不做一些更复杂的改变。

    选项 2

    从主查询中删除子查询,您必须将它们放在 execute() 中。像这样的:

    for(sObject s : scope){
        Territory_Master__c tm = (Territory_Master__c) s;
    
        for(Territory_User__c uu : [SELECT User__c FROM Territory_User__c WHERE Territory_Master__c = :tm.Id]){
            for(Territory_Account__c aa: [SELECT Account__c FROM Territory_Account__c WHERE Territory_Master__c = :tm.Id]){
                acctMembers.add(new AccountTeamMember(
                    AccountId = aa.Account__c,
                    TeamMemberRole = 'Sales Rep',
                    UserId = uu.User__c)
                );
    
                acctSharingRules.add(new AccountShare(
                    AccountId = aa.Account__c,
                    OpportunityAccessLevel = 'Read',
                    CaseAccessLevel = 'Read',
                    AccountAccessLevel = 'Edit',
                    UserOrGroupId = uu.User__c)
                );
            }
        }
    }
    

    旁注

    1. 您是否有可能在所有对象(区域主/用户/帐户)中检索到 50K 行的限制?如果是这种情况,您可能必须限制批处理作业的范围(传递给Database.executeBatch())。
    2. 这个技巧可以让你的脚本执行得更快一些并且使用更少的语句(这样你就不会达到另一个调控器限制):

      acctSharingRules.add(new AccountShare(
          AccountId = aa.Account__c,
          OpportunityAccessLevel = 'Read',
          CaseAccessLevel = 'Read',
          AccountAccessLevel = 'Edit',
          UserOrGroupId = uu.User__c)
      );
      

    【讨论】:

    • 非常有帮助的答案。不幸的是,选项 1 的行为与我的原始代码一样,但您使用选项 2 完成了它。我稍微修改了您的代码以适应逻辑,最终结果完美无缺。我还考虑了你的旁注。感谢您的帮助。
    • 很高兴能提供帮助,而且我自己也学到了一些东西 :) 实际上我有一个脑残的时刻。忽略大约读取 50K 行的位。您最担心的应该是在每个上下文中插入 10K 行(因此每个 execute() 调用);)
    【解决方案2】:

    那里的代码没有明显的问题,所以如果我是你,我会尝试缩小问题的原因。问题的根源将是以下之一:

    • 您的查询仅返回 accountList 或 userList 或两者中的 100 个项目
    • 插件一次只能处理 100 个项目,并且静默无法插入其余项目
    • 100 之后的项目插入失败

    如果您还没有这样做,您应该熟悉在 Salesforce.com 中使用调试日志(设置 | 监控 | 调试日志)。打开它们,然后运行这段代码并在其中调用一些 System.debug 来弄清楚:

    • userList 和 accountList 中有多少项?
    • 如果超过 100 个,当您插入共享行时,其中一些插入会失败吗?如果您使用 Database.insert() 而不仅仅是插入语句,那么您将得到一个 SaveResult[] 返回,它将告诉您尝试插入的每一行是成功还是错误。

    所以我不能说为什么会失败,而且我没有看到任何应该适用于此的特定限制,但以上内容至少应该可以帮助您调试它。

    【讨论】:

    • 感谢您的回答。我只需稍微重新编码就可以让它工作。
    猜你喜欢
    • 2020-02-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-09-20
    • 1970-01-01
    • 2021-05-25
    • 2023-04-06
    • 1970-01-01
    相关资源
    最近更新 更多