2

我对 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;
}
}
4

2 回答 2

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'))

那是因为以这种方式编写的 for 循环应该自动调用它们的内部 queryMore()

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

选项 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)
    );
    
于 2013-01-10T20:10:42.627 回答
0

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

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

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

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

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

于 2013-01-10T20:06:03.390 回答