0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Apexのベストプラクティス: トリガーコンテキスト変数の適切な使用

Posted at

1. このベストプラクティスのポイント

Apexトリガーでは、Trigger.newTrigger.old などの コンテキスト変数 を使って、レコードの作成・更新・削除時のデータにアクセスできます。

ベストプラクティスとして、トリガーでコンテキスト変数をハンドラクラスに渡す際、適切なデータ型にキャストする必要があります。


2. トリガーコンテキスト変数とは?

📌 主なコンテキスト変数

変数 説明 使えるトリガー
Trigger.new 新しいデータ(リスト) before insert, after insert, before update, after update
Trigger.old 変更前のデータ(リスト) before update, after update, before delete, after delete
Trigger.newMap 新しいデータ(Map) after insert, before update, after update
Trigger.oldMap 変更前のデータ(Map) before update, after update, before delete, after delete

3. ❌ 悪い例(キャストしないまま処理する)

📌 問題のあるコード

public class AccountTriggerHandler {
    public static void processAccounts(List<sObject> records) {
        for (sObject obj : records) {
            System.debug('Account Name: ' + obj.get('Name')); // ❌ 正しいデータ型ではない
        }
    }
}

trigger AccountTrigger on Account (before insert) {
    AccountTriggerHandler.processAccounts(Trigger.new);
}

問題点

  • Trigger.newList<Account> だが、ハンドラメソッドでは List<sObject> として受け取っている。
  • sObject.get('Name') は使えるが、データ型が適切でないため、型チェックが必要になる
  • Account のプロパティ(例えば Industry)にアクセスする際に問題が発生する可能性がある

4. ✅ 良い例(適切にキャストする)

📌 修正コード

public class AccountTriggerHandler {
    public static void processAccounts(List<Account> accounts) {
        for (Account acc : accounts) {
            System.debug('Account Name: ' + acc.Name); // ✅ 型が適切
        }
    }
}

trigger AccountTrigger on Account (before insert) {
    AccountTriggerHandler.processAccounts((List<Account>) Trigger.new); // ✅ キャストして渡す
}

修正のポイント

  • Trigger.newList<Account> にキャストして渡すことで、型チェックの手間を減らし、コードの可読性を向上
  • acc.Name などのプロパティに型変換なしで直接アクセス可能
  • コンパイル時に型チェックされるため、エラーを未然に防ぐことができる

5. Trigger.newMap / Trigger.oldMap を使用する場合

📌 Trigger.newMap を使う場合

public class AccountTriggerHandler {
    public static void processAccountMap(Map<Id, Account> accountMap) {
        for (Account acc : accountMap.values()) {
            System.debug('Processing Account: ' + acc.Name);
        }
    }
}

trigger AccountTrigger on Account (before update) {
    AccountTriggerHandler.processAccountMap((Map<Id, Account>) Trigger.newMap);
}

修正のポイント

  • Trigger.newMapMap<Id, Account> にキャストすることで、Account 型のプロパティに直接アクセス可能。
  • 例えば、特定のAccountの更新があった場合に、Mapを使ってすばやくチェックできる

📌 Trigger.oldMap を使う場合

public class AccountTriggerHandler {
    public static void compareAccountNames(Map<Id, Account> oldAccounts, Map<Id, Account> newAccounts) {
        for (Id accId : oldAccounts.keySet()) {
            if (oldAccounts.get(accId).Name != newAccounts.get(accId).Name) {
                System.debug('Account Name changed from ' + oldAccounts.get(accId).Name + ' to ' + newAccounts.get(accId).Name);
            }
        }
    }
}

trigger AccountTrigger on Account (before update) {
    AccountTriggerHandler.compareAccountNames((Map<Id, Account>) Trigger.oldMap, (Map<Id, Account>) Trigger.newMap);
}

修正のポイント

  • Trigger.oldMapTrigger.newMapMap<Id, Account> にキャスト することで、以前と現在のデータを比較しやすくなる
  • oldAccounts.get(accId).Name のように、安全にアクセスできる

6. まとめ

ポイント 悪い例(NG) 良い例(OK)
キャストをしない List<sObject> のまま処理 (List<Account>) Trigger.new にキャスト
型チェックの手間 sObject.get('Name') を使用 acc.Name のように直接アクセス
可読性 コードが複雑になる 型が明確で、わかりやすい

このベストプラクティスを守ることで、コードが安全かつ分かりやすくなり、エラーを未然に防げる! 🚀

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?