FOR LOOP内でのSOQLを回避する方法

By | July 27, 2021

前書き

「Mapを使え。以上。」で終わりなのですが、あまりに味気ないので実際にありそうな具体例を二つご紹介いたします。

例1:Trigger.newに対するループ内のSOQLを回避する

Bad Example

trigger AccountTrigger on Account(brefore update){
    for(Account acc: Trigger.new){
        List<Contact> contactList = [SELECT Id,Test__c FROM Contact WHERE AccountId =: acc.Id];
        for(Contact con: contactList){
            //取引先責任者に対する任意の処理
        }
    }
}

↑取引先に紐づく取引先責任者を取得するにあたって、forループ内でSOQL文を書いてしまっています。

Good Example

trigger AccountTrigger on Account(brefore update){
    List<Account> accountListWithCountacts = [SELECT Id,(SELECT Id,Test__c FROM Contacts) FROM Account WHERE Id IN:Trigger.newMap.keySet()];
    for(Account acc: accountListWithCountacts){
        for(Contact con: acc.Contacts){
            //取引先責任者に対する任意の処理
        }
    }
}

↑子リレーション名を利用して事前に取引先に紐づく取引先責任者を取得することで、forループ内でのSOQLの記述を回避しています。

例2:SOQLで取得したリストに対するループ内のSOQLを回避する

Bad Example

List<Account> accountList = [SELECT Id FROM Account LIMIT 100];
    for(Account acc: accountList){
        List<Contact> contactList = [SELECT Id,Test__c FROM Contact WHERE AccountId =: acc.Id];
        for(Contact con: contactList){
        //取引先責任者に対する任意の処理
        }
    }
}

↑取引先の子レコードである取引先責任者を取得するにあたって、forループ内でSOQLを書いてしまっています。

Good Example

List<Account> accountList = [SELECT Id FROM Account LIMIT 100];
Map<Id,Account> accountMap = new Map<Id,Account>();
for(Account acc: AccountList){
    accountMap.put(acc.Id,acc);
}
List contactList = [SELECT Id,Test__c FROM Contact WHERE AccounId =: accountMap.keySet()];
for(Contact con: contactList){
//取引先責任者に対する任意の処理
}

↑mapのkeySet()を利用することで、リストで取得した取引先を親に持つ取引先責任者だけの絞り込みを実現し、forループ内でのSOQLを回避しています。