ApexにおけるMapの使いどころ

By | April 10, 2020

Mapの基礎

Map<key, record>を例にとると、代表的なメソッドとして下記が挙げられます。

戻り値メソッド説明
recordput(key, record)mapにkeyとrecordのペアを格納
recordget(key)keyに対応する値を取得
intsize()格納されているペア数を返す
booleanisEmpty()要素数がゼロか判定
booleancontainsKey(key)指定データがkeyに含まれているか判定
booleancontainsValue(record)指定データが値に含まれているか判定
Set<key>keySet()格納されているkeyの一覧を返す
List<Object>values()ペアのすべての値を含むリストを返す

※mapの参照先レコードの値を更新した後、以下のコードでupdate可能

update accountMap.values();

Salesforce開発でMapを使う場面

ユースケースは無数にありますが、ApexにおいてListではなくMapを使う典型的なケースの一つは「idの照合に際して.conteinsKeyメソッドを利用することでfor文を不要にする」というものです。

以下で具体例を二つご紹介したいと思います。

ケース1(商談成約時に自動的に親契約レコードを自動生成)

trigger TriggerContractBefore on Opportunity (before update) {

    Map<String, Opportunity> createContract = new Map<String, Opportunity>();

    for (Opportunity record : Trigger.new) {
        if (
            record.StageName == '成約' &&
            record.StageName <> trigger.oldMap.get(record.Id).StageName
            ){
                System.debug('--- TriggerContractBefore : createContract --- #Record : ' + record.Id);
                createContract.put(record.AccountId, record);
           }
    }

    if (createContract.isEmpty() == false) {
        List<Contract__c> insertContract = new List<Contract__c>();
        for (Opportunity record : createContract.values()) {
            insertContract.add(new Contract__c(
                AccountId = record.AccountId,
                Name = record.AccountName__c + '契約'
            ));
        }

        insert insertContract;

        for (Contract__c contract : insertContract) {
            Opportunity record = createContract.get(contract.AccountId);
            record.Contract__c = contract.Id;     
        }       
}

商談成約時に契約レコードを自動生成したあと、当該の商談を契約に紐づけるコードです。

mapを利用することで、契約レコード生成後に起点となった商談を契約に紐づけ直すところがスマートになっているのが分かるかと思います。

ケース2(レコード同士の値の一致判定)

List<Account> accountList = [Select Id, Name From Account];
List<Contact> contactList = [Select Name, AccountId From Contact];
Map<Id, Account> accountMap = new Map<Id, Account>(accountList);
for (Contact con : contactList) {
  if(accountMap.containsKey(con.AccountId)) {
    //なにか処理
  }
} 

for文でListを二つネストさせて回し、そこで両者の値を比較して処理を行っていくパターンの場合、Mapを利用するとforループが一つ減り、ガバナ制限への抵触を回避することが可能です。